X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=gdb%2Ftarget-descriptions.c;h=85954ac29395eae25cc222b26f958f7d1e99a83f;hb=09cb5e2312e299bd3e362f8acb070560a06d156a;hp=20a3a640f4f8f0016ee57415c8c32289ecce1614;hpb=d0e39ea27cde07011967ab74d39cf13dfe3370c4;p=binutils-gdb.git diff --git a/gdb/target-descriptions.c b/gdb/target-descriptions.c index 20a3a640f4f..85954ac2939 100644 --- a/gdb/target-descriptions.c +++ b/gdb/target-descriptions.c @@ -1,6 +1,6 @@ /* Target description support for GDB. - Copyright (C) 2006-2020 Free Software Foundation, Inc. + Copyright (C) 2006-2022 Free Software Foundation, Inc. Contributed by CodeSourcery. @@ -30,7 +30,7 @@ #include "xml-tdesc.h" #include "osabi.h" -#include "gdb_obstack.h" +#include "gdbsupport/gdb_obstack.h" #include "hashtab.h" #include "inferior.h" #include @@ -141,6 +141,11 @@ make_gdb_type (struct gdbarch *gdbarch, struct tdesc_type *ttype) m_type = arch_float_type (m_gdbarch, -1, "builtin_type_i387_ext", floatformats_i387_ext); return; + + case TDESC_TYPE_BFLOAT16: + m_type = arch_float_type (m_gdbarch, -1, "builtin_type_bfloat16", + floatformats_bfloat16); + return; } internal_error (__FILE__, __LINE__, @@ -225,9 +230,9 @@ make_gdb_type (struct gdbarch *gdbarch, struct tdesc_type *ttype) bitsize = f.end - f.start + 1; total_size = e->size * TARGET_CHAR_BIT; if (gdbarch_byte_order (m_gdbarch) == BFD_ENDIAN_BIG) - SET_FIELD_BITPOS (fld[0], total_size - f.start - bitsize); + fld->set_loc_bitpos (total_size - f.start - bitsize); else - SET_FIELD_BITPOS (fld[0], f.start); + fld->set_loc_bitpos (f.start); FIELD_BITSIZE (fld[0]) = bitsize; } else @@ -258,8 +263,8 @@ make_gdb_type (struct gdbarch *gdbarch, struct tdesc_type *ttype) /* If any of the children of a union are vectors, flag the union as a vector also. This allows e.g. a union of two vector types to show up automatically in "info vector". */ - if (TYPE_VECTOR (field_gdb_type)) - TYPE_VECTOR (m_type) = 1; + if (field_gdb_type->is_vector ()) + m_type->set_is_vector (true); } } @@ -284,7 +289,8 @@ make_gdb_type (struct gdbarch *gdbarch, struct tdesc_type *ttype) m_type = arch_type (m_gdbarch, TYPE_CODE_ENUM, e->size * TARGET_CHAR_BIT, e->name.c_str ()); - TYPE_UNSIGNED (m_type) = 1; + m_type->set_is_unsigned (true); + for (const tdesc_type_field &f : e->fields) { struct field *fld @@ -292,7 +298,7 @@ make_gdb_type (struct gdbarch *gdbarch, struct tdesc_type *ttype) xstrdup (f.name.c_str ()), NULL); - SET_FIELD_BITPOS (fld[0], f.start); + fld->set_loc_enumval (f.start); } } @@ -308,6 +314,29 @@ make_gdb_type (struct gdbarch *gdbarch, struct tdesc_type *ttype) return gdb_type.get_type (); } +/* Wrapper around bfd_arch_info_type. A class with this name is used in + the API that is shared between gdb and gdbserver code, but gdbserver + doesn't use compatibility information, so its version of this class is + empty. */ + +class tdesc_compatible_info +{ +public: + /* Constructor. */ + explicit tdesc_compatible_info (const bfd_arch_info_type *arch) + : m_arch (arch) + { /* Nothing. */ } + + /* Access the contained pointer. */ + const bfd_arch_info_type *arch () const + { return m_arch; } + +private: + /* Architecture information looked up from the entity within + a target description. */ + const bfd_arch_info_type *m_arch; +}; + /* A target description. */ struct target_desc : tdesc_element @@ -328,7 +357,7 @@ struct target_desc : tdesc_element enum gdb_osabi osabi = GDB_OSABI_UNKNOWN; /* The list of compatible architectures reported by the target. */ - std::vector compatible; + std::vector compatible; /* Any architecture-specific properties specified by the target. */ std::vector properties; @@ -417,20 +446,22 @@ struct target_desc_info /* A flag indicating that a description has already been fetched from the target, so it should not be queried again. */ - int fetched; + bool fetched = false; /* The description fetched from the target, or NULL if the target did not supply any description. Only valid when - target_desc_fetched is set. Only the description initialization + FETCHED is set. Only the description initialization code should access this; normally, the description should be accessed through the gdbarch object. */ - const struct target_desc *tdesc; + const struct target_desc *tdesc = nullptr; - /* The filename to read a target description from, as set by "set - tdesc filename ..." */ + /* If not empty, the filename to read a target description from, as set by + "set tdesc filename ...". - char *filename; + If empty, there is not filename specified by the user. */ + + std::string filename; }; /* Get the inferior INF's target description info, allocating one on @@ -440,7 +471,8 @@ static struct target_desc_info * get_tdesc_info (struct inferior *inf) { if (inf->tdesc_info == NULL) - inf->tdesc_info = XCNEW (struct target_desc_info); + inf->tdesc_info = new target_desc_info; + return inf->tdesc_info; } @@ -454,7 +486,7 @@ static struct gdbarch_data *tdesc_data; int target_desc_info_from_user_p (struct target_desc_info *info) { - return info != NULL && info->filename != NULL; + return info != nullptr && !info->filename.empty (); } /* See target-descriptions.h. */ @@ -465,9 +497,7 @@ copy_inferior_target_desc_info (struct inferior *destinf, struct inferior *srcin struct target_desc_info *src = get_tdesc_info (srcinf); struct target_desc_info *dest = get_tdesc_info (destinf); - dest->fetched = src->fetched; - dest->tdesc = src->tdesc; - dest->filename = src->filename != NULL ? xstrdup (src->filename) : NULL; + *dest = *src; } /* See target-descriptions.h. */ @@ -475,25 +505,12 @@ copy_inferior_target_desc_info (struct inferior *destinf, struct inferior *srcin void target_desc_info_free (struct target_desc_info *tdesc_info) { - if (tdesc_info != NULL) - { - xfree (tdesc_info->filename); - xfree (tdesc_info); - } + delete tdesc_info; } -/* Convenience helper macros. */ - -#define target_desc_fetched \ - get_tdesc_info (current_inferior ())->fetched -#define current_target_desc \ - get_tdesc_info (current_inferior ())->tdesc -#define target_description_filename \ - get_tdesc_info (current_inferior ())->filename - /* The string manipulated by the "set tdesc filename ..." command. */ -static char *tdesc_filename_cmd_string; +static std::string tdesc_filename_cmd_string; /* Fetch the current target's description, and switch the current architecture to one which incorporates that description. */ @@ -501,11 +518,13 @@ static char *tdesc_filename_cmd_string; void target_find_description (void) { + target_desc_info *tdesc_info = get_tdesc_info (current_inferior ()); + /* If we've already fetched a description from the target, don't do it again. This allows a target to fetch the description early, during its to_open or to_create_inferior, if it needs extra information about the target to initialize. */ - if (target_desc_fetched) + if (tdesc_info->fetched) return; /* The current architecture should not have any target description @@ -515,29 +534,28 @@ target_find_description (void) /* First try to fetch an XML description from the user-specified file. */ - current_target_desc = NULL; - if (target_description_filename != NULL - && *target_description_filename != '\0') - current_target_desc - = file_read_description_xml (target_description_filename); + tdesc_info->tdesc = nullptr; + if (!tdesc_info->filename.empty ()) + tdesc_info->tdesc = file_read_description_xml (tdesc_info->filename.data ()); /* Next try to read the description from the current target using target objects. */ - if (current_target_desc == NULL) - current_target_desc = target_read_description_xml (current_top_target ()); + if (tdesc_info->tdesc == nullptr) + tdesc_info->tdesc = target_read_description_xml + (current_inferior ()->top_target ()); /* If that failed try a target-specific hook. */ - if (current_target_desc == NULL) - current_target_desc = target_read_description (current_top_target ()); + if (tdesc_info->tdesc == nullptr) + tdesc_info->tdesc = target_read_description + (current_inferior ()->top_target ()); /* If a non-NULL description was returned, then update the current architecture. */ - if (current_target_desc) + if (tdesc_info->tdesc != nullptr) { struct gdbarch_info info; - gdbarch_info_init (&info); - info.target_desc = current_target_desc; + info.target_desc = tdesc_info->tdesc; if (!gdbarch_update_p (info)) warning (_("Architecture rejected target-supplied description")); else @@ -546,7 +564,7 @@ target_find_description (void) data = ((struct tdesc_arch_data *) gdbarch_data (target_gdbarch (), tdesc_data)); - if (tdesc_has_registers (current_target_desc) + if (tdesc_has_registers (tdesc_info->tdesc) && data->arch_regs.empty ()) warning (_("Target-supplied registers are not supported " "by the current architecture")); @@ -555,7 +573,7 @@ target_find_description (void) /* Now that we know this description is usable, record that we fetched it. */ - target_desc_fetched = 1; + tdesc_info->fetched = true; } /* Discard any description fetched from the current target, and switch @@ -564,15 +582,15 @@ target_find_description (void) void target_clear_description (void) { - struct gdbarch_info info; + target_desc_info *tdesc_info = get_tdesc_info (current_inferior ()); - if (!target_desc_fetched) + if (!tdesc_info->fetched) return; - target_desc_fetched = 0; - current_target_desc = NULL; + tdesc_info->fetched = false; + tdesc_info->tdesc = nullptr; - gdbarch_info_init (&info); + gdbarch_info info; if (!gdbarch_update_p (info)) internal_error (__FILE__, __LINE__, _("Could not remove target-supplied description")); @@ -585,8 +603,10 @@ target_clear_description (void) const struct target_desc * target_current_description (void) { - if (target_desc_fetched) - return current_target_desc; + target_desc_info *tdesc_info = get_tdesc_info (current_inferior ()); + + if (tdesc_info->fetched) + return tdesc_info->tdesc; return NULL; } @@ -598,11 +618,11 @@ int tdesc_compatible_p (const struct target_desc *target_desc, const struct bfd_arch_info *arch) { - for (const bfd_arch_info *compat : target_desc->compatible) + for (const tdesc_compatible_info_up &compat : target_desc->compatible) { - if (compat == arch - || arch->compatible (arch, compat) - || compat->compatible (compat, arch)) + if (compat->arch () == arch + || arch->compatible (arch, compat->arch ()) + || compat->arch ()->compatible (compat->arch (), arch)) return 1; } @@ -639,7 +659,25 @@ tdesc_architecture (const struct target_desc *target_desc) const char * tdesc_architecture_name (const struct target_desc *target_desc) { - return target_desc->arch->printable_name; + if (target_desc->arch != NULL) + return target_desc->arch->printable_name; + return NULL; +} + +/* See gdbsupport/tdesc.h. */ + +const std::vector & +tdesc_compatible_info_list (const target_desc *target_desc) +{ + return target_desc->compatible; +} + +/* See gdbsupport/tdesc.h. */ + +const char * +tdesc_compatible_info_arch_name (const tdesc_compatible_info_up &compatible) +{ + return compatible->arch ()->printable_name; } /* Return the OSABI associated with this target description, or @@ -732,21 +770,17 @@ tdesc_data_init (struct obstack *obstack) /* Similar, but for the temporary copy used during architecture initialization. */ -struct tdesc_arch_data * +tdesc_arch_data_up tdesc_data_alloc (void) { - return new tdesc_arch_data (); + return tdesc_arch_data_up (new tdesc_arch_data ()); } -/* Free something allocated by tdesc_data_alloc, if it is not going - to be used (for instance if it was unsuitable for the - architecture). */ +/* See target-descriptions.h. */ void -tdesc_data_cleanup (void *data_untyped) +tdesc_arch_data_deleter::operator() (struct tdesc_arch_data *data) const { - struct tdesc_arch_data *data = (struct tdesc_arch_data *) data_untyped; - delete data; } @@ -973,12 +1007,12 @@ tdesc_remote_register_number (struct gdbarch *gdbarch, int regno) int tdesc_register_in_reggroup_p (struct gdbarch *gdbarch, int regno, - struct reggroup *reggroup) + const struct reggroup *reggroup) { struct tdesc_reg *reg = tdesc_find_register (gdbarch, regno); if (reg != NULL && !reg->group.empty () - && (reg->group == reggroup_name (reggroup))) + && (reg->group == reggroup->name ())) return 1; if (reg != NULL @@ -994,7 +1028,7 @@ tdesc_register_in_reggroup_p (struct gdbarch *gdbarch, int regno, static int tdesc_register_reggroup_p (struct gdbarch *gdbarch, int regno, - struct reggroup *reggroup) + const struct reggroup *reggroup) { int num_regs = gdbarch_num_regs (gdbarch); int num_pseudo_regs = gdbarch_num_pseudo_regs (gdbarch); @@ -1056,11 +1090,11 @@ set_tdesc_pseudo_register_reggroup_p void tdesc_use_registers (struct gdbarch *gdbarch, const struct target_desc *target_desc, - struct tdesc_arch_data *early_data) + tdesc_arch_data_up &&early_data, + tdesc_unknown_register_ftype unk_reg_cb) { int num_regs = gdbarch_num_regs (gdbarch); struct tdesc_arch_data *data; - htab_t reg_hash; /* We can't use the description for registers if it doesn't describe any. This function should only be called after validating @@ -1069,17 +1103,17 @@ tdesc_use_registers (struct gdbarch *gdbarch, gdb_assert (tdesc_has_registers (target_desc)); data = (struct tdesc_arch_data *) gdbarch_data (gdbarch, tdesc_data); - data->arch_regs = early_data->arch_regs; - delete early_data; + data->arch_regs = std::move (early_data->arch_regs); /* Build up a set of all registers, so that we can assign register numbers where needed. The hash table expands as necessary, so the initial size is arbitrary. */ - reg_hash = htab_create (37, htab_hash_pointer, htab_eq_pointer, NULL); + htab_up reg_hash (htab_create (37, htab_hash_pointer, htab_eq_pointer, + NULL)); for (const tdesc_feature_up &feature : target_desc->features) for (const tdesc_reg_up ® : feature->registers) { - void **slot = htab_find_slot (reg_hash, reg.get (), INSERT); + void **slot = htab_find_slot (reg_hash.get (), reg.get (), INSERT); *slot = reg.get (); /* Add reggroup if its new. */ @@ -1094,7 +1128,7 @@ tdesc_use_registers (struct gdbarch *gdbarch, architecture. */ for (const tdesc_arch_reg &arch_reg : data->arch_regs) if (arch_reg.reg != NULL) - htab_remove_elt (reg_hash, arch_reg.reg); + htab_remove_elt (reg_hash.get (), arch_reg.reg); /* Assign numbers to the remaining registers and add them to the list of registers. The new numbers are always above gdbarch_num_regs. @@ -1105,16 +1139,42 @@ tdesc_use_registers (struct gdbarch *gdbarch, while (data->arch_regs.size () < num_regs) data->arch_regs.emplace_back (nullptr, nullptr); + /* First we give the target a chance to number previously unknown + registers. This allows targets to record the numbers assigned based + on which feature the register was from. */ + if (unk_reg_cb != NULL) + { + for (const tdesc_feature_up &feature : target_desc->features) + for (const tdesc_reg_up ® : feature->registers) + if (htab_find (reg_hash.get (), reg.get ()) != NULL) + { + int regno = unk_reg_cb (gdbarch, feature.get (), + reg->name.c_str (), num_regs); + gdb_assert (regno == -1 || regno >= num_regs); + if (regno != -1) + { + while (regno >= data->arch_regs.size ()) + data->arch_regs.emplace_back (nullptr, nullptr); + data->arch_regs[regno] = tdesc_arch_reg (reg.get (), NULL); + num_regs = regno + 1; + htab_remove_elt (reg_hash.get (), reg.get ()); + } + } + } + + /* Ensure the array was sized correctly above. */ + gdb_assert (data->arch_regs.size () == num_regs); + + /* Now in a final pass we assign register numbers to any remaining + unnumbered registers. */ for (const tdesc_feature_up &feature : target_desc->features) for (const tdesc_reg_up ® : feature->registers) - if (htab_find (reg_hash, reg.get ()) != NULL) + if (htab_find (reg_hash.get (), reg.get ()) != NULL) { data->arch_regs.emplace_back (reg.get (), nullptr); num_regs++; } - htab_delete (reg_hash); - /* Update the architecture. */ set_gdbarch_num_regs (gdbarch, num_regs); set_gdbarch_register_name (gdbarch, tdesc_register_name); @@ -1136,12 +1196,16 @@ tdesc_create_feature (struct target_desc *tdesc, const char *name) return new_feature; } -struct target_desc * +/* See gdbsupport/tdesc.h. */ + +target_desc_up allocate_target_description (void) { - return new target_desc (); + return target_desc_up (new target_desc ()); } +/* See gdbsupport/tdesc.h. */ + void target_desc_deleter::operator() (struct target_desc *target_desc) const { @@ -1158,14 +1222,16 @@ tdesc_add_compatible (struct target_desc *target_desc, if (compatible == NULL) return; - for (const bfd_arch_info *compat : target_desc->compatible) - if (compat == compatible) + for (const tdesc_compatible_info_up &compat : target_desc->compatible) + if (compat->arch () == compatible) internal_error (__FILE__, __LINE__, _("Attempted to add duplicate " "compatible architecture \"%s\""), compatible->printable_name); - target_desc->compatible.push_back (compatible); + target_desc->compatible.push_back + (std::unique_ptr + (new tdesc_compatible_info (compatible))); } void @@ -1221,8 +1287,9 @@ static void set_tdesc_filename_cmd (const char *args, int from_tty, struct cmd_list_element *c) { - xfree (target_description_filename); - target_description_filename = xstrdup (tdesc_filename_cmd_string); + target_desc_info *tdesc_info = get_tdesc_info (current_inferior ()); + + tdesc_info->filename = tdesc_filename_cmd_string; target_clear_description (); target_find_description (); @@ -1233,21 +1300,24 @@ show_tdesc_filename_cmd (struct ui_file *file, int from_tty, struct cmd_list_element *c, const char *value) { - value = target_description_filename; + value = get_tdesc_info (current_inferior ())->filename.data (); if (value != NULL && *value != '\0') - printf_filtered (_("The target description will be read from \"%s\".\n"), - value); + gdb_printf (file, + _("The target description will be read from \"%s\".\n"), + value); else - printf_filtered (_("The target description will be " - "read from the target.\n")); + gdb_printf (file, + _("The target description will be " + "read from the target.\n")); } static void unset_tdesc_filename_cmd (const char *args, int from_tty) { - xfree (target_description_filename); - target_description_filename = NULL; + target_desc_info *tdesc_info = get_tdesc_info (current_inferior ()); + + tdesc_info->filename.clear (); target_clear_description (); target_find_description (); } @@ -1270,14 +1340,16 @@ public: break; else if (*inp == '-') *outp++ = '_'; + else if (*inp == ' ') + *outp++ = '_'; else *outp++ = *inp; *outp = '\0'; /* Standard boilerplate. */ - printf_unfiltered ("/* THIS FILE IS GENERATED. " - "-*- buffer-read-only: t -*- vi" - ":set ro:\n"); + gdb_printf ("/* THIS FILE IS GENERATED. " + "-*- buffer-read-only: t -*- vi" + ":set ro:\n"); } ~print_c_tdesc () @@ -1287,56 +1359,56 @@ public: void visit_pre (const target_desc *e) override { - printf_unfiltered (" Original: %s */\n\n", - lbasename (m_filename_after_features.c_str ())); + gdb_printf (" Original: %s */\n\n", + lbasename (m_filename_after_features.c_str ())); - printf_unfiltered ("#include \"defs.h\"\n"); - printf_unfiltered ("#include \"osabi.h\"\n"); - printf_unfiltered ("#include \"target-descriptions.h\"\n"); - printf_unfiltered ("\n"); + gdb_printf ("#include \"defs.h\"\n"); + gdb_printf ("#include \"osabi.h\"\n"); + gdb_printf ("#include \"target-descriptions.h\"\n"); + gdb_printf ("\n"); - printf_unfiltered ("struct target_desc *tdesc_%s;\n", m_function); - printf_unfiltered ("static void\n"); - printf_unfiltered ("initialize_tdesc_%s (void)\n", m_function); - printf_unfiltered ("{\n"); - printf_unfiltered - (" struct target_desc *result = allocate_target_description ();\n"); + gdb_printf ("struct target_desc *tdesc_%s;\n", m_function); + gdb_printf ("static void\n"); + gdb_printf ("initialize_tdesc_%s (void)\n", m_function); + gdb_printf ("{\n"); + gdb_printf + (" target_desc_up result = allocate_target_description ();\n"); if (tdesc_architecture (e) != NULL) { - printf_unfiltered - (" set_tdesc_architecture (result, bfd_scan_arch (\"%s\"));\n", + gdb_printf + (" set_tdesc_architecture (result.get (), bfd_scan_arch (\"%s\"));\n", tdesc_architecture (e)->printable_name); - printf_unfiltered ("\n"); + gdb_printf ("\n"); } if (tdesc_osabi (e) > GDB_OSABI_UNKNOWN && tdesc_osabi (e) < GDB_OSABI_INVALID) { - printf_unfiltered - (" set_tdesc_osabi (result, osabi_from_tdesc_string (\"%s\"));\n", + gdb_printf + (" set_tdesc_osabi (result.get (), osabi_from_tdesc_string (\"%s\"));\n", gdbarch_osabi_name (tdesc_osabi (e))); - printf_unfiltered ("\n"); + gdb_printf ("\n"); } - for (const bfd_arch_info_type *compatible : e->compatible) - printf_unfiltered - (" tdesc_add_compatible (result, bfd_scan_arch (\"%s\"));\n", - compatible->printable_name); + for (const tdesc_compatible_info_up &compatible : e->compatible) + gdb_printf + (" tdesc_add_compatible (result.get (), bfd_scan_arch (\"%s\"));\n", + compatible->arch ()->printable_name); if (!e->compatible.empty ()) - printf_unfiltered ("\n"); + gdb_printf ("\n"); for (const property &prop : e->properties) - printf_unfiltered (" set_tdesc_property (result, \"%s\", \"%s\");\n", - prop.key.c_str (), prop.value.c_str ()); + gdb_printf (" set_tdesc_property (result.get (), \"%s\", \"%s\");\n", + prop.key.c_str (), prop.value.c_str ()); - printf_unfiltered (" struct tdesc_feature *feature;\n"); + gdb_printf (" struct tdesc_feature *feature;\n"); } void visit_pre (const tdesc_feature *e) override { - printf_unfiltered ("\n feature = tdesc_create_feature (result, \"%s\");\n", - e->name.c_str ()); + gdb_printf ("\n feature = tdesc_create_feature (result.get (), \"%s\");\n", + e->name.c_str ()); } void visit_post (const tdesc_feature *e) override @@ -1344,8 +1416,8 @@ public: void visit_post (const target_desc *e) override { - printf_unfiltered ("\n tdesc_%s = result;\n", m_function); - printf_unfiltered ("}\n"); + gdb_printf ("\n tdesc_%s = result.release ();\n", m_function); + gdb_printf ("}\n"); } void visit (const tdesc_type_builtin *type) override @@ -1357,25 +1429,25 @@ public: { if (!m_printed_element_type) { - printf_unfiltered (" tdesc_type *element_type;\n"); + gdb_printf (" tdesc_type *element_type;\n"); m_printed_element_type = true; } - printf_unfiltered + gdb_printf (" element_type = tdesc_named_type (feature, \"%s\");\n", type->element_type->name.c_str ()); - printf_unfiltered + gdb_printf (" tdesc_create_vector (feature, \"%s\", element_type, %d);\n", type->name.c_str (), type->count); - printf_unfiltered ("\n"); + gdb_printf ("\n"); } void visit (const tdesc_type_with_fields *type) override { if (!m_printed_type_with_fields) { - printf_unfiltered (" tdesc_type_with_fields *type_with_fields;\n"); + gdb_printf (" tdesc_type_with_fields *type_with_fields;\n"); m_printed_type_with_fields = true; } @@ -1385,16 +1457,16 @@ public: case TDESC_TYPE_FLAGS: if (type->kind == TDESC_TYPE_STRUCT) { - printf_unfiltered + gdb_printf (" type_with_fields = tdesc_create_struct (feature, \"%s\");\n", type->name.c_str ()); if (type->size != 0) - printf_unfiltered + gdb_printf (" tdesc_set_struct_size (type_with_fields, %d);\n", type->size); } else { - printf_unfiltered + gdb_printf (" type_with_fields = tdesc_create_flags (feature, \"%s\", %d);\n", type->name.c_str (), type->size); } @@ -1413,7 +1485,7 @@ public: if (f.type->kind == TDESC_TYPE_BOOL) { gdb_assert (f.start == f.end); - printf_unfiltered + gdb_printf (" tdesc_add_flag (type_with_fields, %d, \"%s\");\n", f.start, f.name.c_str ()); } @@ -1421,7 +1493,7 @@ public: || (type->size == 8 && f.type->kind == TDESC_TYPE_UINT64)) { - printf_unfiltered + gdb_printf (" tdesc_add_bitfield (type_with_fields, \"%s\", %d, %d);\n", f.name.c_str (), f.start, f.end); } @@ -1430,7 +1502,7 @@ public: printf_field_type_assignment ("tdesc_named_type (feature, \"%s\");\n", type_name); - printf_unfiltered + gdb_printf (" tdesc_add_typed_bitfield (type_with_fields, \"%s\"," " %d, %d, field_type);\n", f.name.c_str (), f.start, f.end); @@ -1442,31 +1514,31 @@ public: gdb_assert (type->kind == TDESC_TYPE_STRUCT); printf_field_type_assignment ("tdesc_named_type (feature, \"%s\");\n", type_name); - printf_unfiltered + gdb_printf (" tdesc_add_field (type_with_fields, \"%s\", field_type);\n", f.name.c_str ()); } } break; case TDESC_TYPE_UNION: - printf_unfiltered + gdb_printf (" type_with_fields = tdesc_create_union (feature, \"%s\");\n", type->name.c_str ()); for (const tdesc_type_field &f : type->fields) { printf_field_type_assignment ("tdesc_named_type (feature, \"%s\");\n", f.type->name.c_str ()); - printf_unfiltered + gdb_printf (" tdesc_add_field (type_with_fields, \"%s\", field_type);\n", f.name.c_str ()); } break; case TDESC_TYPE_ENUM: - printf_unfiltered + gdb_printf (" type_with_fields = tdesc_create_enum (feature, \"%s\", %d);\n", type->name.c_str (), type->size); for (const tdesc_type_field &f : type->fields) - printf_unfiltered + gdb_printf (" tdesc_add_enum_value (type_with_fields, %d, \"%s\");\n", f.start, f.name.c_str ()); break; @@ -1474,19 +1546,19 @@ public: error (_("C output is not supported type \"%s\"."), type->name.c_str ()); } - printf_unfiltered ("\n"); + gdb_printf ("\n"); } void visit (const tdesc_reg *reg) override { - printf_unfiltered (" tdesc_create_reg (feature, \"%s\", %ld, %d, ", - reg->name.c_str (), reg->target_regnum, - reg->save_restore); + gdb_printf (" tdesc_create_reg (feature, \"%s\", %ld, %d, ", + reg->name.c_str (), reg->target_regnum, + reg->save_restore); if (!reg->group.empty ()) - printf_unfiltered ("\"%s\", ", reg->group.c_str ()); + gdb_printf ("\"%s\", ", reg->group.c_str ()); else - printf_unfiltered ("NULL, "); - printf_unfiltered ("%d, \"%s\");\n", reg->bitsize, reg->type.c_str ()); + gdb_printf ("NULL, "); + gdb_printf ("%d, \"%s\");\n", reg->bitsize, reg->type.c_str ()); } protected: @@ -1501,15 +1573,15 @@ private: { if (!m_printed_field_type) { - printf_unfiltered (" tdesc_type *field_type;\n"); + gdb_printf (" tdesc_type *field_type;\n"); m_printed_field_type = true; } - printf_unfiltered (" field_type = "); + gdb_printf (" field_type = "); va_list args; va_start (args, fmt); - vprintf_unfiltered (fmt, args); + gdb_vprintf (fmt, args); va_end (args); } @@ -1541,11 +1613,11 @@ public: void visit_pre (const target_desc *e) override { - printf_unfiltered (" Original: %s */\n\n", - lbasename (m_filename_after_features.c_str ())); + gdb_printf (" Original: %s */\n\n", + lbasename (m_filename_after_features.c_str ())); - printf_unfiltered ("#include \"gdbsupport/tdesc.h\"\n"); - printf_unfiltered ("\n"); + gdb_printf ("#include \"gdbsupport/tdesc.h\"\n"); + gdb_printf ("\n"); } void visit_post (const target_desc *e) override @@ -1561,22 +1633,22 @@ public: std::replace (name.begin (), name.end (), '/', '_'); std::replace (name.begin (), name.end (), '-', '_'); - printf_unfiltered ("static int\n"); - printf_unfiltered ("create_feature_%s ", name.c_str ()); - printf_unfiltered ("(struct target_desc *result, long regnum)\n"); + gdb_printf ("static int\n"); + gdb_printf ("create_feature_%s ", name.c_str ()); + gdb_printf ("(struct target_desc *result, long regnum)\n"); - printf_unfiltered ("{\n"); - printf_unfiltered (" struct tdesc_feature *feature;\n"); + gdb_printf ("{\n"); + gdb_printf (" struct tdesc_feature *feature;\n"); - printf_unfiltered + gdb_printf ("\n feature = tdesc_create_feature (result, \"%s\");\n", e->name.c_str ()); } void visit_post (const tdesc_feature *e) override { - printf_unfiltered (" return regnum;\n"); - printf_unfiltered ("}\n"); + gdb_printf (" return regnum;\n"); + gdb_printf ("}\n"); } void visit (const tdesc_reg *reg) override @@ -1609,27 +1681,27 @@ public: and also print the message so that it can be saved in the generated c file. */ - printf_unfiltered ("ERROR: \"regnum\" attribute %ld ", - reg->target_regnum); - printf_unfiltered ("is not the largest number (%d).\n", - m_next_regnum); + gdb_printf ("ERROR: \"regnum\" attribute %ld ", + reg->target_regnum); + gdb_printf ("is not the largest number (%d).\n", + m_next_regnum); error (_("\"regnum\" attribute %ld is not the largest number (%d)."), reg->target_regnum, m_next_regnum); } if (reg->target_regnum > m_next_regnum) { - printf_unfiltered (" regnum = %ld;\n", reg->target_regnum); + gdb_printf (" regnum = %ld;\n", reg->target_regnum); m_next_regnum = reg->target_regnum; } - printf_unfiltered (" tdesc_create_reg (feature, \"%s\", regnum++, %d, ", - reg->name.c_str (), reg->save_restore); + gdb_printf (" tdesc_create_reg (feature, \"%s\", regnum++, %d, ", + reg->name.c_str (), reg->save_restore); if (!reg->group.empty ()) - printf_unfiltered ("\"%s\", ", reg->group.c_str ()); + gdb_printf ("\"%s\", ", reg->group.c_str ()); else - printf_unfiltered ("NULL, "); - printf_unfiltered ("%d, \"%s\");\n", reg->bitsize, reg->type.c_str ()); + gdb_printf ("NULL, "); + gdb_printf ("%d, \"%s\");\n", reg->bitsize, reg->type.c_str ()); m_next_regnum++; } @@ -1654,20 +1726,54 @@ tdesc_get_features_xml (const target_desc *tdesc) return tdesc->xmltarget; } +/* Data structures and functions to setup the option flags for 'maintenance + print c-tdesc command. */ + +struct maint_print_c_tdesc_options +{ + /* True when the '-single-feature' flag was passed. */ + bool single_feature = false; +}; + +using maint_print_c_tdesc_opt_def + = gdb::option::flag_option_def; + +static const gdb::option::option_def maint_print_c_tdesc_opt_defs[] = { + maint_print_c_tdesc_opt_def { + "single-feature", + [] (maint_print_c_tdesc_options *opt) { return &opt->single_feature; }, + N_("Print C description of just a single feature.") + }, +}; + +static inline gdb::option::option_def_group +make_maint_print_c_tdesc_options_def_group (maint_print_c_tdesc_options *opts) +{ + return {{maint_print_c_tdesc_opt_defs}, opts}; +} + +/* Implement 'maintenance print c-tdesc' command. */ + static void maint_print_c_tdesc_cmd (const char *args, int from_tty) { const struct target_desc *tdesc; const char *filename; + maint_print_c_tdesc_options opts; + auto grp = make_maint_print_c_tdesc_options_def_group (&opts); + gdb::option::process_options + (&args, gdb::option::PROCESS_OPTIONS_UNKNOWN_IS_ERROR, grp); + if (args == NULL) { /* Use the global target-supplied description, not the current architecture's. This lets a GDB for one architecture generate C for another architecture's description, even though the gdbarch initialization code will reject the new description. */ - tdesc = current_target_desc; - filename = target_description_filename; + target_desc_info *tdesc_info = get_tdesc_info (current_inferior ()); + tdesc = tdesc_info->tdesc; + filename = tdesc_info->filename.data (); } else { @@ -1680,7 +1786,7 @@ maint_print_c_tdesc_cmd (const char *args, int from_tty) error (_("There is no target description to print.")); if (filename == NULL) - error (_("The current target description did not come from an XML file.")); + filename = "fetched from target"; std::string filename_after_features (filename); auto loc = filename_after_features.rfind ("/features/"); @@ -1691,15 +1797,12 @@ maint_print_c_tdesc_cmd (const char *args, int from_tty) /* Print c files for target features instead of target descriptions, because c files got from target features are more flexible than the counterparts. */ - if (startswith (filename_after_features.c_str (), "i386/32bit-") - || startswith (filename_after_features.c_str (), "i386/64bit-") - || startswith (filename_after_features.c_str (), "i386/x32-core.xml") - || startswith (filename_after_features.c_str (), "riscv/") - || startswith (filename_after_features.c_str (), "tic6x-") - || startswith (filename_after_features.c_str (), "aarch64") - || startswith (filename_after_features.c_str (), "arm/") - || startswith (filename_after_features.c_str (), "arc/")) + if (opts.single_feature) { + if (tdesc->features.size () != 1) + error (_("only target descriptions with 1 feature can be used " + "with -single-feature option")); + print_c_feature v (filename_after_features); tdesc->accept (v); @@ -1712,6 +1815,52 @@ maint_print_c_tdesc_cmd (const char *args, int from_tty) } } +/* Completer for the "backtrace" command. */ + +static void +maint_print_c_tdesc_cmd_completer (struct cmd_list_element *ignore, + completion_tracker &tracker, + const char *text, const char *word) +{ + auto grp = make_maint_print_c_tdesc_options_def_group (nullptr); + if (gdb::option::complete_options + (tracker, &text, gdb::option::PROCESS_OPTIONS_UNKNOWN_IS_ERROR, grp)) + return; + + word = advance_to_filename_complete_word_point (tracker, text); + filename_completer (ignore, tracker, text, word); +} + +/* Implement the maintenance print xml-tdesc command. */ + +static void +maint_print_xml_tdesc_cmd (const char *args, int from_tty) +{ + const struct target_desc *tdesc; + + if (args == NULL) + { + /* Use the global target-supplied description, not the current + architecture's. This lets a GDB for one architecture generate XML + for another architecture's description, even though the gdbarch + initialization code will reject the new description. */ + tdesc = get_tdesc_info (current_inferior ())->tdesc; + } + else + { + /* Use the target description from the XML file. */ + tdesc = file_read_description_xml (args); + } + + if (tdesc == NULL) + error (_("There is no target description to print.")); + + std::string buf; + print_xml_feature v (&buf); + tdesc->accept (v); + gdb_puts (buf.c_str ()); +} + namespace selftests { /* A reference target description, used for testing (see record_xml_tdesc). */ @@ -1751,8 +1900,8 @@ maintenance_check_tdesc_xml_convert (const target_desc *tdesc, const char *name) if (xml == nullptr || *xml != '@') { - printf_filtered (_("Could not convert description for %s to xml.\n"), - name); + gdb_printf (_("Could not convert description for %s to xml.\n"), + name); return false; } @@ -1760,14 +1909,14 @@ maintenance_check_tdesc_xml_convert (const target_desc *tdesc, const char *name) if (tdesc_trans == nullptr) { - printf_filtered (_("Could not convert description for %s from xml.\n"), - name); + gdb_printf (_("Could not convert description for %s from xml.\n"), + name); return false; } else if (*tdesc != *tdesc_trans) { - printf_filtered (_("Converted description for %s does not match.\n"), - name); + gdb_printf (_("Converted description for %s does not match.\n"), + name); return false; } return true; @@ -1796,34 +1945,34 @@ maintenance_check_xml_descriptions (const char *dir, int from_tty) if (tdesc == NULL || *tdesc != *e.tdesc) { - printf_filtered ( _("Descriptions for %s do not match.\n"), e.name); + gdb_printf ( _("Descriptions for %s do not match.\n"), e.name); failed++; } else if (!maintenance_check_tdesc_xml_convert (tdesc, e.name) || !maintenance_check_tdesc_xml_convert (e.tdesc.get (), e.name)) failed++; } - printf_filtered (_("Tested %lu XML files, %d failed\n"), - (long) selftests::xml_tdesc.size (), failed); + gdb_printf (_("Tested %lu XML files, %d failed\n"), + (long) selftests::xml_tdesc.size (), failed); } void _initialize_target_descriptions (); void _initialize_target_descriptions () { + cmd_list_element *cmd; + tdesc_data = gdbarch_data_register_pre_init (tdesc_data_init); - add_basic_prefix_cmd ("tdesc", class_maintenance, _("\ -Set target description specific variables."), - &tdesc_set_cmdlist, "set tdesc ", - 0 /* allow-unknown */, &setlist); - add_show_prefix_cmd ("tdesc", class_maintenance, _("\ -Show target description specific variables."), - &tdesc_show_cmdlist, "show tdesc ", - 0 /* allow-unknown */, &showlist); + add_setshow_prefix_cmd ("tdesc", class_maintenance, + _("Set target description specific variables."), + _("Show target description specific variables."), + &tdesc_set_cmdlist, &tdesc_show_cmdlist, + &setlist, &showlist); + add_basic_prefix_cmd ("tdesc", class_maintenance, _("\ Unset target description specific variables."), - &tdesc_unset_cmdlist, "unset tdesc ", + &tdesc_unset_cmdlist, 0 /* allow-unknown */, &unsetlist); add_setshow_filename_cmd ("filename", class_obscure, @@ -1842,11 +1991,30 @@ Unset the file to read for an XML target description.\n\ When unset, GDB will read the description from the target."), &tdesc_unset_cmdlist); - add_cmd ("c-tdesc", class_maintenance, maint_print_c_tdesc_cmd, _("\ -Print the current target description as a C source file."), - &maintenanceprintlist); - - cmd_list_element *cmd; + auto grp = make_maint_print_c_tdesc_options_def_group (nullptr); + static std::string help_text + = gdb::option::build_help (_("\ +Print the current target description as a C source file.\n\ +Usage: maintenance print c-tdesc [OPTION] [FILENAME]\n\ +\n\ +Options:\n\ +%OPTIONS%\n\ +\n\ +When FILENAME is not provided then print the current target\n\ +description, otherwise an XML target description is read from\n\ +FILENAME and printed as a C function.\n\ +\n\ +When '-single-feature' is used then the target description should\n\ +contain a single feature and the generated C code will only create\n\ +that feature within an already existing target_desc object."), grp); + cmd = add_cmd ("c-tdesc", class_maintenance, maint_print_c_tdesc_cmd, + help_text.c_str (), &maintenanceprintlist); + set_cmd_completer_handle_brkchars (cmd, maint_print_c_tdesc_cmd_completer); + + cmd = add_cmd ("xml-tdesc", class_maintenance, maint_print_xml_tdesc_cmd, _("\ +Print the current target description as an XML file."), + &maintenanceprintlist); + set_cmd_completer (cmd, filename_completer); cmd = add_cmd ("xml-descriptions", class_maintenance, maintenance_check_xml_descriptions, _("\