12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027 |
- /* Target description support for GDB.
- Copyright (C) 2006-2022 Free Software Foundation, Inc.
- Contributed by CodeSourcery.
- 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 "arch-utils.h"
- #include "gdbcmd.h"
- #include "gdbtypes.h"
- #include "reggroups.h"
- #include "target.h"
- #include "target-descriptions.h"
- #include "xml-support.h"
- #include "xml-tdesc.h"
- #include "osabi.h"
- #include "gdbsupport/gdb_obstack.h"
- #include "hashtab.h"
- #include "inferior.h"
- #include <algorithm>
- #include "completer.h"
- #include "readline/tilde.h" /* tilde_expand */
- /* Types. */
- struct property
- {
- property (const std::string &key_, const std::string &value_)
- : key (key_), value (value_)
- {}
- std::string key;
- std::string value;
- };
- /* Convert a tdesc_type to a gdb type. */
- static type *
- make_gdb_type (struct gdbarch *gdbarch, struct tdesc_type *ttype)
- {
- class gdb_type_creator : public tdesc_element_visitor
- {
- public:
- gdb_type_creator (struct gdbarch *gdbarch)
- : m_gdbarch (gdbarch)
- {}
- type *get_type ()
- {
- return m_type;
- }
- void visit (const tdesc_type_builtin *e) override
- {
- switch (e->kind)
- {
- /* Predefined types. */
- case TDESC_TYPE_BOOL:
- m_type = builtin_type (m_gdbarch)->builtin_bool;
- return;
- case TDESC_TYPE_INT8:
- m_type = builtin_type (m_gdbarch)->builtin_int8;
- return;
- case TDESC_TYPE_INT16:
- m_type = builtin_type (m_gdbarch)->builtin_int16;
- return;
- case TDESC_TYPE_INT32:
- m_type = builtin_type (m_gdbarch)->builtin_int32;
- return;
- case TDESC_TYPE_INT64:
- m_type = builtin_type (m_gdbarch)->builtin_int64;
- return;
- case TDESC_TYPE_INT128:
- m_type = builtin_type (m_gdbarch)->builtin_int128;
- return;
- case TDESC_TYPE_UINT8:
- m_type = builtin_type (m_gdbarch)->builtin_uint8;
- return;
- case TDESC_TYPE_UINT16:
- m_type = builtin_type (m_gdbarch)->builtin_uint16;
- return;
- case TDESC_TYPE_UINT32:
- m_type = builtin_type (m_gdbarch)->builtin_uint32;
- return;
- case TDESC_TYPE_UINT64:
- m_type = builtin_type (m_gdbarch)->builtin_uint64;
- return;
- case TDESC_TYPE_UINT128:
- m_type = builtin_type (m_gdbarch)->builtin_uint128;
- return;
- case TDESC_TYPE_CODE_PTR:
- m_type = builtin_type (m_gdbarch)->builtin_func_ptr;
- return;
- case TDESC_TYPE_DATA_PTR:
- m_type = builtin_type (m_gdbarch)->builtin_data_ptr;
- return;
- }
- m_type = tdesc_find_type (m_gdbarch, e->name.c_str ());
- if (m_type != NULL)
- return;
- switch (e->kind)
- {
- case TDESC_TYPE_IEEE_HALF:
- m_type = arch_float_type (m_gdbarch, -1, "builtin_type_ieee_half",
- floatformats_ieee_half);
- return;
- case TDESC_TYPE_IEEE_SINGLE:
- m_type = arch_float_type (m_gdbarch, -1, "builtin_type_ieee_single",
- floatformats_ieee_single);
- return;
- case TDESC_TYPE_IEEE_DOUBLE:
- m_type = arch_float_type (m_gdbarch, -1, "builtin_type_ieee_double",
- floatformats_ieee_double);
- return;
- case TDESC_TYPE_ARM_FPA_EXT:
- m_type = arch_float_type (m_gdbarch, -1, "builtin_type_arm_ext",
- floatformats_arm_ext);
- return;
- case TDESC_TYPE_I387_EXT:
- 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__,
- "Type \"%s\" has an unknown kind %d",
- e->name.c_str (), e->kind);
- }
- void visit (const tdesc_type_vector *e) override
- {
- m_type = tdesc_find_type (m_gdbarch, e->name.c_str ());
- if (m_type != NULL)
- return;
- type *element_gdb_type = make_gdb_type (m_gdbarch, e->element_type);
- m_type = init_vector_type (element_gdb_type, e->count);
- m_type->set_name (xstrdup (e->name.c_str ()));
- return;
- }
- void visit (const tdesc_type_with_fields *e) override
- {
- m_type = tdesc_find_type (m_gdbarch, e->name.c_str ());
- if (m_type != NULL)
- return;
- switch (e->kind)
- {
- case TDESC_TYPE_STRUCT:
- make_gdb_type_struct (e);
- return;
- case TDESC_TYPE_UNION:
- make_gdb_type_union (e);
- return;
- case TDESC_TYPE_FLAGS:
- make_gdb_type_flags (e);
- return;
- case TDESC_TYPE_ENUM:
- make_gdb_type_enum (e);
- return;
- }
- internal_error (__FILE__, __LINE__,
- "Type \"%s\" has an unknown kind %d",
- e->name.c_str (), e->kind);
- }
- private:
- void make_gdb_type_struct (const tdesc_type_with_fields *e)
- {
- m_type = arch_composite_type (m_gdbarch, NULL, TYPE_CODE_STRUCT);
- m_type->set_name (xstrdup (e->name.c_str ()));
- for (const tdesc_type_field &f : e->fields)
- {
- if (f.start != -1 && f.end != -1)
- {
- /* Bitfield. */
- struct field *fld;
- struct type *field_gdb_type;
- int bitsize, total_size;
- /* This invariant should be preserved while creating types. */
- gdb_assert (e->size != 0);
- if (f.type != NULL)
- field_gdb_type = make_gdb_type (m_gdbarch, f.type);
- else if (e->size > 4)
- field_gdb_type = builtin_type (m_gdbarch)->builtin_uint64;
- else
- field_gdb_type = builtin_type (m_gdbarch)->builtin_uint32;
- fld = append_composite_type_field_raw
- (m_type, xstrdup (f.name.c_str ()), field_gdb_type);
- /* For little-endian, BITPOS counts from the LSB of
- the structure and marks the LSB of the field. For
- big-endian, BITPOS counts from the MSB of the
- structure and marks the MSB of the field. Either
- way, it is the number of bits to the "left" of the
- field. To calculate this in big-endian, we need
- the total size of the structure. */
- bitsize = f.end - f.start + 1;
- total_size = e->size * TARGET_CHAR_BIT;
- if (gdbarch_byte_order (m_gdbarch) == BFD_ENDIAN_BIG)
- fld->set_loc_bitpos (total_size - f.start - bitsize);
- else
- fld->set_loc_bitpos (f.start);
- FIELD_BITSIZE (fld[0]) = bitsize;
- }
- else
- {
- gdb_assert (f.start == -1 && f.end == -1);
- type *field_gdb_type = make_gdb_type (m_gdbarch, f.type);
- append_composite_type_field (m_type,
- xstrdup (f.name.c_str ()),
- field_gdb_type);
- }
- }
- if (e->size != 0)
- TYPE_LENGTH (m_type) = e->size;
- }
- void make_gdb_type_union (const tdesc_type_with_fields *e)
- {
- m_type = arch_composite_type (m_gdbarch, NULL, TYPE_CODE_UNION);
- m_type->set_name (xstrdup (e->name.c_str ()));
- for (const tdesc_type_field &f : e->fields)
- {
- type* field_gdb_type = make_gdb_type (m_gdbarch, f.type);
- append_composite_type_field (m_type, xstrdup (f.name.c_str ()),
- field_gdb_type);
- /* 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 (field_gdb_type->is_vector ())
- m_type->set_is_vector (true);
- }
- }
- void make_gdb_type_flags (const tdesc_type_with_fields *e)
- {
- m_type = arch_flags_type (m_gdbarch, e->name.c_str (),
- e->size * TARGET_CHAR_BIT);
- for (const tdesc_type_field &f : e->fields)
- {
- int bitsize = f.end - f.start + 1;
- gdb_assert (f.type != NULL);
- type *field_gdb_type = make_gdb_type (m_gdbarch, f.type);
- append_flags_type_field (m_type, f.start, bitsize,
- field_gdb_type, f.name.c_str ());
- }
- }
- void make_gdb_type_enum (const tdesc_type_with_fields *e)
- {
- m_type = arch_type (m_gdbarch, TYPE_CODE_ENUM, e->size * TARGET_CHAR_BIT,
- e->name.c_str ());
- m_type->set_is_unsigned (true);
- for (const tdesc_type_field &f : e->fields)
- {
- struct field *fld
- = append_composite_type_field_raw (m_type,
- xstrdup (f.name.c_str ()),
- NULL);
- fld->set_loc_enumval (f.start);
- }
- }
- /* The gdbarch used. */
- struct gdbarch *m_gdbarch;
- /* The type created. */
- type *m_type;
- };
- gdb_type_creator gdb_type (gdbarch);
- ttype->accept (gdb_type);
- 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 <compatible> entity within
- a target description. */
- const bfd_arch_info_type *m_arch;
- };
- /* A target description. */
- struct target_desc : tdesc_element
- {
- target_desc ()
- {}
- virtual ~target_desc () = default;
- target_desc (const target_desc &) = delete;
- void operator= (const target_desc &) = delete;
- /* The architecture reported by the target, if any. */
- const struct bfd_arch_info *arch = NULL;
- /* The osabi reported by the target, if any; GDB_OSABI_UNKNOWN
- otherwise. */
- enum gdb_osabi osabi = GDB_OSABI_UNKNOWN;
- /* The list of compatible architectures reported by the target. */
- std::vector<tdesc_compatible_info_up> compatible;
- /* Any architecture-specific properties specified by the target. */
- std::vector<property> properties;
- /* The features associated with this target. */
- std::vector<tdesc_feature_up> features;
- /* Used to cache the generated xml version of the target description. */
- mutable char *xmltarget = nullptr;
- void accept (tdesc_element_visitor &v) const override
- {
- v.visit_pre (this);
- for (const tdesc_feature_up &feature : features)
- feature->accept (v);
- v.visit_post (this);
- }
- bool operator== (const target_desc &other) const
- {
- if (arch != other.arch)
- return false;
- if (osabi != other.osabi)
- return false;
- if (features.size () != other.features.size ())
- return false;
- for (int ix = 0; ix < features.size (); ix++)
- {
- const tdesc_feature_up &feature1 = features[ix];
- const tdesc_feature_up &feature2 = other.features[ix];
- if (feature1 != feature2 && *feature1 != *feature2)
- return false;
- }
- return true;
- }
- bool operator!= (const target_desc &other) const
- {
- return !(*this == other);
- }
- };
- /* Per-architecture data associated with a target description. The
- target description may be shared by multiple architectures, but
- this data is private to one gdbarch. */
- struct tdesc_arch_reg
- {
- tdesc_arch_reg (tdesc_reg *reg_, struct type *type_)
- : reg (reg_), type (type_)
- {}
- struct tdesc_reg *reg;
- struct type *type;
- };
- struct tdesc_arch_data
- {
- /* A list of register/type pairs, indexed by GDB's internal register number.
- During initialization of the gdbarch this list is used to store
- registers which the architecture assigns a fixed register number.
- Registers which are NULL in this array, or off the end, are
- treated as zero-sized and nameless (i.e. placeholders in the
- numbering). */
- std::vector<tdesc_arch_reg> arch_regs;
- /* Functions which report the register name, type, and reggroups for
- pseudo-registers. */
- gdbarch_register_name_ftype *pseudo_register_name = NULL;
- gdbarch_register_type_ftype *pseudo_register_type = NULL;
- gdbarch_register_reggroup_p_ftype *pseudo_register_reggroup_p = NULL;
- };
- /* Info about an inferior's target description. There's one of these
- for each inferior. */
- struct target_desc_info
- {
- /* A flag indicating that a description has already been fetched
- from the target, so it should not be queried again. */
- bool fetched = false;
- /* The description fetched from the target, or NULL if the target
- did not supply any description. Only valid when
- 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 = nullptr;
- /* If not empty, the filename to read a target description from, as set by
- "set tdesc 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
- the stop if necessary. */
- static struct target_desc_info *
- get_tdesc_info (struct inferior *inf)
- {
- if (inf->tdesc_info == NULL)
- inf->tdesc_info = new target_desc_info;
- return inf->tdesc_info;
- }
- /* A handle for architecture-specific data associated with the
- target description (see struct tdesc_arch_data). */
- static struct gdbarch_data *tdesc_data;
- /* See target-descriptions.h. */
- int
- target_desc_info_from_user_p (struct target_desc_info *info)
- {
- return info != nullptr && !info->filename.empty ();
- }
- /* See target-descriptions.h. */
- void
- copy_inferior_target_desc_info (struct inferior *destinf, struct inferior *srcinf)
- {
- struct target_desc_info *src = get_tdesc_info (srcinf);
- struct target_desc_info *dest = get_tdesc_info (destinf);
- *dest = *src;
- }
- /* See target-descriptions.h. */
- void
- target_desc_info_free (struct target_desc_info *tdesc_info)
- {
- delete tdesc_info;
- }
- /* The string manipulated by the "set tdesc filename ..." command. */
- static std::string tdesc_filename_cmd_string;
- /* Fetch the current target's description, and switch the current
- architecture to one which incorporates that description. */
- 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 (tdesc_info->fetched)
- return;
- /* The current architecture should not have any target description
- specified. It should have been cleared, e.g. when we
- disconnected from the previous target. */
- gdb_assert (gdbarch_target_desc (target_gdbarch ()) == NULL);
- /* First try to fetch an XML description from the user-specified
- file. */
- 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 (tdesc_info->tdesc == nullptr)
- tdesc_info->tdesc = target_read_description_xml
- (current_inferior ()->top_target ());
- /* If that failed try a target-specific hook. */
- 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 (tdesc_info->tdesc != nullptr)
- {
- struct gdbarch_info info;
- info.target_desc = tdesc_info->tdesc;
- if (!gdbarch_update_p (info))
- warning (_("Architecture rejected target-supplied description"));
- else
- {
- struct tdesc_arch_data *data;
- data = ((struct tdesc_arch_data *)
- gdbarch_data (target_gdbarch (), tdesc_data));
- if (tdesc_has_registers (tdesc_info->tdesc)
- && data->arch_regs.empty ())
- warning (_("Target-supplied registers are not supported "
- "by the current architecture"));
- }
- }
- /* Now that we know this description is usable, record that we
- fetched it. */
- tdesc_info->fetched = true;
- }
- /* Discard any description fetched from the current target, and switch
- the current architecture to one with no target description. */
- void
- target_clear_description (void)
- {
- target_desc_info *tdesc_info = get_tdesc_info (current_inferior ());
- if (!tdesc_info->fetched)
- return;
- tdesc_info->fetched = false;
- tdesc_info->tdesc = nullptr;
- gdbarch_info info;
- if (!gdbarch_update_p (info))
- internal_error (__FILE__, __LINE__,
- _("Could not remove target-supplied description"));
- }
- /* Return the global current target description. This should only be
- used by gdbarch initialization code; most access should be through
- an existing gdbarch. */
- const struct target_desc *
- target_current_description (void)
- {
- target_desc_info *tdesc_info = get_tdesc_info (current_inferior ());
- if (tdesc_info->fetched)
- return tdesc_info->tdesc;
- return NULL;
- }
- /* Return non-zero if this target description is compatible
- with the given BFD architecture. */
- int
- tdesc_compatible_p (const struct target_desc *target_desc,
- const struct bfd_arch_info *arch)
- {
- for (const tdesc_compatible_info_up &compat : target_desc->compatible)
- {
- if (compat->arch () == arch
- || arch->compatible (arch, compat->arch ())
- || compat->arch ()->compatible (compat->arch (), arch))
- return 1;
- }
- return 0;
- }
- /* Direct accessors for target descriptions. */
- /* Return the string value of a property named KEY, or NULL if the
- property was not specified. */
- const char *
- tdesc_property (const struct target_desc *target_desc, const char *key)
- {
- for (const property &prop : target_desc->properties)
- if (prop.key == key)
- return prop.value.c_str ();
- return NULL;
- }
- /* Return the BFD architecture associated with this target
- description, or NULL if no architecture was specified. */
- const struct bfd_arch_info *
- tdesc_architecture (const struct target_desc *target_desc)
- {
- return target_desc->arch;
- }
- /* See gdbsupport/tdesc.h. */
- const char *
- tdesc_architecture_name (const struct target_desc *target_desc)
- {
- if (target_desc->arch != NULL)
- return target_desc->arch->printable_name;
- return NULL;
- }
- /* See gdbsupport/tdesc.h. */
- const std::vector<tdesc_compatible_info_up> &
- 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
- GDB_OSABI_UNKNOWN if no osabi was specified. */
- enum gdb_osabi
- tdesc_osabi (const struct target_desc *target_desc)
- {
- return target_desc->osabi;
- }
- /* See gdbsupport/tdesc.h. */
- const char *
- tdesc_osabi_name (const struct target_desc *target_desc)
- {
- enum gdb_osabi osabi = tdesc_osabi (target_desc);
- if (osabi > GDB_OSABI_UNKNOWN && osabi < GDB_OSABI_INVALID)
- return gdbarch_osabi_name (osabi);
- return nullptr;
- }
- /* Return 1 if this target description includes any registers. */
- int
- tdesc_has_registers (const struct target_desc *target_desc)
- {
- if (target_desc == NULL)
- return 0;
- for (const tdesc_feature_up &feature : target_desc->features)
- if (!feature->registers.empty ())
- return 1;
- return 0;
- }
- /* Return the feature with the given name, if present, or NULL if
- the named feature is not found. */
- const struct tdesc_feature *
- tdesc_find_feature (const struct target_desc *target_desc,
- const char *name)
- {
- for (const tdesc_feature_up &feature : target_desc->features)
- if (feature->name == name)
- return feature.get ();
- return NULL;
- }
- /* Return the name of FEATURE. */
- const char *
- tdesc_feature_name (const struct tdesc_feature *feature)
- {
- return feature->name.c_str ();
- }
- /* Lookup type associated with ID. */
- struct type *
- tdesc_find_type (struct gdbarch *gdbarch, const char *id)
- {
- tdesc_arch_data *data
- = (struct tdesc_arch_data *) gdbarch_data (gdbarch, tdesc_data);
- for (const tdesc_arch_reg ® : data->arch_regs)
- {
- if (reg.reg
- && reg.reg->tdesc_type
- && reg.type
- && reg.reg->tdesc_type->name == id)
- return reg.type;
- }
- return NULL;
- }
- /* Support for registers from target descriptions. */
- /* Construct the per-gdbarch data. */
- static void *
- tdesc_data_init (struct obstack *obstack)
- {
- return obstack_new<tdesc_arch_data> (obstack);
- }
- /* Similar, but for the temporary copy used during architecture
- initialization. */
- tdesc_arch_data_up
- tdesc_data_alloc (void)
- {
- return tdesc_arch_data_up (new tdesc_arch_data ());
- }
- /* See target-descriptions.h. */
- void
- tdesc_arch_data_deleter::operator() (struct tdesc_arch_data *data) const
- {
- delete data;
- }
- /* Search FEATURE for a register named NAME. */
- static struct tdesc_reg *
- tdesc_find_register_early (const struct tdesc_feature *feature,
- const char *name)
- {
- for (const tdesc_reg_up ® : feature->registers)
- if (strcasecmp (reg->name.c_str (), name) == 0)
- return reg.get ();
- return NULL;
- }
- /* Search FEATURE for a register named NAME. Assign REGNO to it. */
- int
- tdesc_numbered_register (const struct tdesc_feature *feature,
- struct tdesc_arch_data *data,
- int regno, const char *name)
- {
- struct tdesc_reg *reg = tdesc_find_register_early (feature, name);
- if (reg == NULL)
- return 0;
- /* Make sure the vector includes a REGNO'th element. */
- while (regno >= data->arch_regs.size ())
- data->arch_regs.emplace_back (nullptr, nullptr);
- data->arch_regs[regno] = tdesc_arch_reg (reg, NULL);
- return 1;
- }
- /* Search FEATURE for a register named NAME, but do not assign a fixed
- register number to it. */
- int
- tdesc_unnumbered_register (const struct tdesc_feature *feature,
- const char *name)
- {
- struct tdesc_reg *reg = tdesc_find_register_early (feature, name);
- if (reg == NULL)
- return 0;
- return 1;
- }
- /* Search FEATURE for a register whose name is in NAMES and assign
- REGNO to it. */
- int
- tdesc_numbered_register_choices (const struct tdesc_feature *feature,
- struct tdesc_arch_data *data,
- int regno, const char *const names[])
- {
- int i;
- for (i = 0; names[i] != NULL; i++)
- if (tdesc_numbered_register (feature, data, regno, names[i]))
- return 1;
- return 0;
- }
- /* Search FEATURE for a register named NAME, and return its size in
- bits. The register must exist. */
- int
- tdesc_register_bitsize (const struct tdesc_feature *feature, const char *name)
- {
- struct tdesc_reg *reg = tdesc_find_register_early (feature, name);
- gdb_assert (reg != NULL);
- return reg->bitsize;
- }
- /* Look up a register by its GDB internal register number. */
- static struct tdesc_arch_reg *
- tdesc_find_arch_register (struct gdbarch *gdbarch, int regno)
- {
- struct tdesc_arch_data *data;
- data = (struct tdesc_arch_data *) gdbarch_data (gdbarch, tdesc_data);
- if (regno < data->arch_regs.size ())
- return &data->arch_regs[regno];
- else
- return NULL;
- }
- static struct tdesc_reg *
- tdesc_find_register (struct gdbarch *gdbarch, int regno)
- {
- struct tdesc_arch_reg *reg = tdesc_find_arch_register (gdbarch, regno);
- return reg? reg->reg : NULL;
- }
- /* Return the name of register REGNO, from the target description or
- from an architecture-provided pseudo_register_name method. */
- const char *
- tdesc_register_name (struct gdbarch *gdbarch, int regno)
- {
- struct tdesc_reg *reg = tdesc_find_register (gdbarch, regno);
- int num_regs = gdbarch_num_regs (gdbarch);
- if (reg != NULL)
- return reg->name.c_str ();
- if (regno >= num_regs && regno < gdbarch_num_cooked_regs (gdbarch))
- {
- struct tdesc_arch_data *data
- = (struct tdesc_arch_data *) gdbarch_data (gdbarch, tdesc_data);
- gdb_assert (data->pseudo_register_name != NULL);
- return data->pseudo_register_name (gdbarch, regno);
- }
- return "";
- }
- struct type *
- tdesc_register_type (struct gdbarch *gdbarch, int regno)
- {
- struct tdesc_arch_reg *arch_reg = tdesc_find_arch_register (gdbarch, regno);
- struct tdesc_reg *reg = arch_reg? arch_reg->reg : NULL;
- int num_regs = gdbarch_num_regs (gdbarch);
- int num_pseudo_regs = gdbarch_num_pseudo_regs (gdbarch);
- if (reg == NULL && regno >= num_regs && regno < num_regs + num_pseudo_regs)
- {
- struct tdesc_arch_data *data
- = (struct tdesc_arch_data *) gdbarch_data (gdbarch, tdesc_data);
- gdb_assert (data->pseudo_register_type != NULL);
- return data->pseudo_register_type (gdbarch, regno);
- }
- if (reg == NULL)
- /* Return "int0_t", since "void" has a misleading size of one. */
- return builtin_type (gdbarch)->builtin_int0;
- if (arch_reg->type == NULL)
- {
- /* First check for a predefined or target defined type. */
- if (reg->tdesc_type)
- arch_reg->type = make_gdb_type (gdbarch, reg->tdesc_type);
- /* Next try size-sensitive type shortcuts. */
- else if (reg->type == "float")
- {
- if (reg->bitsize == gdbarch_float_bit (gdbarch))
- arch_reg->type = builtin_type (gdbarch)->builtin_float;
- else if (reg->bitsize == gdbarch_double_bit (gdbarch))
- arch_reg->type = builtin_type (gdbarch)->builtin_double;
- else if (reg->bitsize == gdbarch_long_double_bit (gdbarch))
- arch_reg->type = builtin_type (gdbarch)->builtin_long_double;
- else
- {
- warning (_("Register \"%s\" has an unsupported size (%d bits)"),
- reg->name.c_str (), reg->bitsize);
- arch_reg->type = builtin_type (gdbarch)->builtin_double;
- }
- }
- else if (reg->type == "int")
- {
- if (reg->bitsize == gdbarch_long_bit (gdbarch))
- arch_reg->type = builtin_type (gdbarch)->builtin_long;
- else if (reg->bitsize == TARGET_CHAR_BIT)
- arch_reg->type = builtin_type (gdbarch)->builtin_char;
- else if (reg->bitsize == gdbarch_short_bit (gdbarch))
- arch_reg->type = builtin_type (gdbarch)->builtin_short;
- else if (reg->bitsize == gdbarch_int_bit (gdbarch))
- arch_reg->type = builtin_type (gdbarch)->builtin_int;
- else if (reg->bitsize == gdbarch_long_long_bit (gdbarch))
- arch_reg->type = builtin_type (gdbarch)->builtin_long_long;
- else if (reg->bitsize == gdbarch_ptr_bit (gdbarch))
- /* A bit desperate by this point... */
- arch_reg->type = builtin_type (gdbarch)->builtin_data_ptr;
- else
- {
- warning (_("Register \"%s\" has an unsupported size (%d bits)"),
- reg->name.c_str (), reg->bitsize);
- arch_reg->type = builtin_type (gdbarch)->builtin_long;
- }
- }
- if (arch_reg->type == NULL)
- internal_error (__FILE__, __LINE__,
- "Register \"%s\" has an unknown type \"%s\"",
- reg->name.c_str (), reg->type.c_str ());
- }
- return arch_reg->type;
- }
- static int
- tdesc_remote_register_number (struct gdbarch *gdbarch, int regno)
- {
- struct tdesc_reg *reg = tdesc_find_register (gdbarch, regno);
- if (reg != NULL)
- return reg->target_regnum;
- else
- return -1;
- }
- /* Check whether REGNUM is a member of REGGROUP. Registers from the
- target description may be classified as general, float, vector or other
- register groups registered with reggroup_add(). Unlike a gdbarch
- register_reggroup_p method, this function will return -1 if it does not
- know; the caller should handle registers with no specified group.
- The names of containing features are not used. This might be extended
- to display registers in some more useful groupings.
- The save-restore flag is also implemented here. */
- int
- tdesc_register_in_reggroup_p (struct gdbarch *gdbarch, int regno,
- const struct reggroup *reggroup)
- {
- struct tdesc_reg *reg = tdesc_find_register (gdbarch, regno);
- if (reg != NULL && !reg->group.empty ()
- && (reg->group == reggroup->name ()))
- return 1;
- if (reg != NULL
- && (reggroup == save_reggroup || reggroup == restore_reggroup))
- return reg->save_restore;
- return -1;
- }
- /* Check whether REGNUM is a member of REGGROUP. Registers with no
- group specified go to the default reggroup function and are handled
- by type. */
- static int
- tdesc_register_reggroup_p (struct gdbarch *gdbarch, int regno,
- const struct reggroup *reggroup)
- {
- int num_regs = gdbarch_num_regs (gdbarch);
- int num_pseudo_regs = gdbarch_num_pseudo_regs (gdbarch);
- int ret;
- if (regno >= num_regs && regno < num_regs + num_pseudo_regs)
- {
- struct tdesc_arch_data *data
- = (struct tdesc_arch_data *) gdbarch_data (gdbarch, tdesc_data);
- if (data->pseudo_register_reggroup_p != NULL)
- return data->pseudo_register_reggroup_p (gdbarch, regno, reggroup);
- /* Otherwise fall through to the default reggroup_p. */
- }
- ret = tdesc_register_in_reggroup_p (gdbarch, regno, reggroup);
- if (ret != -1)
- return ret;
- return default_register_reggroup_p (gdbarch, regno, reggroup);
- }
- /* Record architecture-specific functions to call for pseudo-register
- support. */
- void
- set_tdesc_pseudo_register_name (struct gdbarch *gdbarch,
- gdbarch_register_name_ftype *pseudo_name)
- {
- struct tdesc_arch_data *data
- = (struct tdesc_arch_data *) gdbarch_data (gdbarch, tdesc_data);
- data->pseudo_register_name = pseudo_name;
- }
- void
- set_tdesc_pseudo_register_type (struct gdbarch *gdbarch,
- gdbarch_register_type_ftype *pseudo_type)
- {
- struct tdesc_arch_data *data
- = (struct tdesc_arch_data *) gdbarch_data (gdbarch, tdesc_data);
- data->pseudo_register_type = pseudo_type;
- }
- void
- set_tdesc_pseudo_register_reggroup_p
- (struct gdbarch *gdbarch,
- gdbarch_register_reggroup_p_ftype *pseudo_reggroup_p)
- {
- struct tdesc_arch_data *data
- = (struct tdesc_arch_data *) gdbarch_data (gdbarch, tdesc_data);
- data->pseudo_register_reggroup_p = pseudo_reggroup_p;
- }
- /* Update GDBARCH to use the target description for registers. */
- void
- tdesc_use_registers (struct gdbarch *gdbarch,
- const struct target_desc *target_desc,
- 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;
- /* We can't use the description for registers if it doesn't describe
- any. This function should only be called after validating
- registers, so the caller should know that registers are
- included. */
- gdb_assert (tdesc_has_registers (target_desc));
- data = (struct tdesc_arch_data *) gdbarch_data (gdbarch, tdesc_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. */
- 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.get (), reg.get (), INSERT);
- *slot = reg.get ();
- /* Add reggroup if its new. */
- if (!reg->group.empty ())
- if (reggroup_find (gdbarch, reg->group.c_str ()) == NULL)
- reggroup_add (gdbarch, reggroup_gdbarch_new (gdbarch,
- reg->group.c_str (),
- USER_REGGROUP));
- }
- /* Remove any registers which were assigned numbers by the
- architecture. */
- for (const tdesc_arch_reg &arch_reg : data->arch_regs)
- if (arch_reg.reg != NULL)
- 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.
- Iterate over the features, not the hash table, so that the order
- matches that in the target description. */
- gdb_assert (data->arch_regs.size () <= num_regs);
- 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.get (), reg.get ()) != NULL)
- {
- data->arch_regs.emplace_back (reg.get (), nullptr);
- num_regs++;
- }
- /* Update the architecture. */
- set_gdbarch_num_regs (gdbarch, num_regs);
- set_gdbarch_register_name (gdbarch, tdesc_register_name);
- set_gdbarch_register_type (gdbarch, tdesc_register_type);
- set_gdbarch_remote_register_number (gdbarch,
- tdesc_remote_register_number);
- set_gdbarch_register_reggroup_p (gdbarch, tdesc_register_reggroup_p);
- }
- /* See gdbsupport/tdesc.h. */
- struct tdesc_feature *
- tdesc_create_feature (struct target_desc *tdesc, const char *name)
- {
- struct tdesc_feature *new_feature = new tdesc_feature (name);
- tdesc->features.emplace_back (new_feature);
- return new_feature;
- }
- /* See gdbsupport/tdesc.h. */
- target_desc_up
- allocate_target_description (void)
- {
- return target_desc_up (new target_desc ());
- }
- /* See gdbsupport/tdesc.h. */
- void
- target_desc_deleter::operator() (struct target_desc *target_desc) const
- {
- delete target_desc;
- }
- void
- tdesc_add_compatible (struct target_desc *target_desc,
- const struct bfd_arch_info *compatible)
- {
- /* If this instance of GDB is compiled without BFD support for the
- compatible architecture, simply ignore it -- we would not be able
- to handle it anyway. */
- if (compatible == NULL)
- return;
- 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
- (std::unique_ptr<tdesc_compatible_info>
- (new tdesc_compatible_info (compatible)));
- }
- void
- set_tdesc_property (struct target_desc *target_desc,
- const char *key, const char *value)
- {
- gdb_assert (key != NULL && value != NULL);
- if (tdesc_property (target_desc, key) != NULL)
- internal_error (__FILE__, __LINE__,
- _("Attempted to add duplicate property \"%s\""), key);
- target_desc->properties.emplace_back (key, value);
- }
- /* See gdbsupport/tdesc.h. */
- void
- set_tdesc_architecture (struct target_desc *target_desc,
- const char *name)
- {
- set_tdesc_architecture (target_desc, bfd_scan_arch (name));
- }
- void
- set_tdesc_architecture (struct target_desc *target_desc,
- const struct bfd_arch_info *arch)
- {
- target_desc->arch = arch;
- }
- /* See gdbsupport/tdesc.h. */
- void
- set_tdesc_osabi (struct target_desc *target_desc, const char *name)
- {
- set_tdesc_osabi (target_desc, osabi_from_tdesc_string (name));
- }
- void
- set_tdesc_osabi (struct target_desc *target_desc, enum gdb_osabi osabi)
- {
- target_desc->osabi = osabi;
- }
- static struct cmd_list_element *tdesc_set_cmdlist, *tdesc_show_cmdlist;
- static struct cmd_list_element *tdesc_unset_cmdlist;
- /* Helper functions for the CLI commands. */
- static void
- set_tdesc_filename_cmd (const char *args, int from_tty,
- struct cmd_list_element *c)
- {
- target_desc_info *tdesc_info = get_tdesc_info (current_inferior ());
- tdesc_info->filename = tdesc_filename_cmd_string;
- target_clear_description ();
- target_find_description ();
- }
- static void
- show_tdesc_filename_cmd (struct ui_file *file, int from_tty,
- struct cmd_list_element *c,
- const char *value)
- {
- value = get_tdesc_info (current_inferior ())->filename.data ();
- if (value != NULL && *value != '\0')
- gdb_printf (file,
- _("The target description will be read from \"%s\".\n"),
- value);
- else
- 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)
- {
- target_desc_info *tdesc_info = get_tdesc_info (current_inferior ());
- tdesc_info->filename.clear ();
- target_clear_description ();
- target_find_description ();
- }
- /* Print target description in C. */
- class print_c_tdesc : public tdesc_element_visitor
- {
- public:
- print_c_tdesc (std::string &filename_after_features)
- : m_filename_after_features (filename_after_features)
- {
- const char *inp;
- char *outp;
- const char *filename = lbasename (m_filename_after_features.c_str ());
- m_function = (char *) xmalloc (strlen (filename) + 1);
- for (inp = filename, outp = m_function; *inp != '\0'; inp++)
- if (*inp == '.')
- break;
- else if (*inp == '-')
- *outp++ = '_';
- else if (*inp == ' ')
- *outp++ = '_';
- else
- *outp++ = *inp;
- *outp = '\0';
- /* Standard boilerplate. */
- gdb_printf ("/* THIS FILE IS GENERATED. "
- "-*- buffer-read-only: t -*- vi"
- ":set ro:\n");
- }
- ~print_c_tdesc ()
- {
- xfree (m_function);
- }
- void visit_pre (const target_desc *e) override
- {
- gdb_printf (" Original: %s */\n\n",
- lbasename (m_filename_after_features.c_str ()));
- gdb_printf ("#include \"defs.h\"\n");
- gdb_printf ("#include \"osabi.h\"\n");
- gdb_printf ("#include \"target-descriptions.h\"\n");
- gdb_printf ("\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)
- {
- gdb_printf
- (" set_tdesc_architecture (result.get (), bfd_scan_arch (\"%s\"));\n",
- tdesc_architecture (e)->printable_name);
- gdb_printf ("\n");
- }
- if (tdesc_osabi (e) > GDB_OSABI_UNKNOWN
- && tdesc_osabi (e) < GDB_OSABI_INVALID)
- {
- gdb_printf
- (" set_tdesc_osabi (result.get (), osabi_from_tdesc_string (\"%s\"));\n",
- gdbarch_osabi_name (tdesc_osabi (e)));
- gdb_printf ("\n");
- }
- 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 ())
- gdb_printf ("\n");
- for (const property &prop : e->properties)
- gdb_printf (" set_tdesc_property (result.get (), \"%s\", \"%s\");\n",
- prop.key.c_str (), prop.value.c_str ());
- gdb_printf (" struct tdesc_feature *feature;\n");
- }
- void visit_pre (const tdesc_feature *e) override
- {
- gdb_printf ("\n feature = tdesc_create_feature (result.get (), \"%s\");\n",
- e->name.c_str ());
- }
- void visit_post (const tdesc_feature *e) override
- {}
- void visit_post (const target_desc *e) override
- {
- gdb_printf ("\n tdesc_%s = result.release ();\n", m_function);
- gdb_printf ("}\n");
- }
- void visit (const tdesc_type_builtin *type) override
- {
- error (_("C output is not supported type \"%s\"."), type->name.c_str ());
- }
- void visit (const tdesc_type_vector *type) override
- {
- if (!m_printed_element_type)
- {
- gdb_printf (" tdesc_type *element_type;\n");
- m_printed_element_type = true;
- }
- gdb_printf
- (" element_type = tdesc_named_type (feature, \"%s\");\n",
- type->element_type->name.c_str ());
- gdb_printf
- (" tdesc_create_vector (feature, \"%s\", element_type, %d);\n",
- type->name.c_str (), type->count);
- gdb_printf ("\n");
- }
- void visit (const tdesc_type_with_fields *type) override
- {
- if (!m_printed_type_with_fields)
- {
- gdb_printf (" tdesc_type_with_fields *type_with_fields;\n");
- m_printed_type_with_fields = true;
- }
- switch (type->kind)
- {
- case TDESC_TYPE_STRUCT:
- case TDESC_TYPE_FLAGS:
- if (type->kind == TDESC_TYPE_STRUCT)
- {
- gdb_printf
- (" type_with_fields = tdesc_create_struct (feature, \"%s\");\n",
- type->name.c_str ());
- if (type->size != 0)
- gdb_printf
- (" tdesc_set_struct_size (type_with_fields, %d);\n", type->size);
- }
- else
- {
- gdb_printf
- (" type_with_fields = tdesc_create_flags (feature, \"%s\", %d);\n",
- type->name.c_str (), type->size);
- }
- for (const tdesc_type_field &f : type->fields)
- {
- const char *type_name;
- gdb_assert (f.type != NULL);
- type_name = f.type->name.c_str ();
- /* To minimize changes to generated files, don't emit type
- info for fields that have defaulted types. */
- if (f.start != -1)
- {
- gdb_assert (f.end != -1);
- if (f.type->kind == TDESC_TYPE_BOOL)
- {
- gdb_assert (f.start == f.end);
- gdb_printf
- (" tdesc_add_flag (type_with_fields, %d, \"%s\");\n",
- f.start, f.name.c_str ());
- }
- else if ((type->size == 4 && f.type->kind == TDESC_TYPE_UINT32)
- || (type->size == 8
- && f.type->kind == TDESC_TYPE_UINT64))
- {
- gdb_printf
- (" tdesc_add_bitfield (type_with_fields, \"%s\", %d, %d);\n",
- f.name.c_str (), f.start, f.end);
- }
- else
- {
- printf_field_type_assignment
- ("tdesc_named_type (feature, \"%s\");\n",
- type_name);
- gdb_printf
- (" tdesc_add_typed_bitfield (type_with_fields, \"%s\","
- " %d, %d, field_type);\n",
- f.name.c_str (), f.start, f.end);
- }
- }
- else /* Not a bitfield. */
- {
- gdb_assert (f.end == -1);
- gdb_assert (type->kind == TDESC_TYPE_STRUCT);
- printf_field_type_assignment
- ("tdesc_named_type (feature, \"%s\");\n", type_name);
- gdb_printf
- (" tdesc_add_field (type_with_fields, \"%s\", field_type);\n",
- f.name.c_str ());
- }
- }
- break;
- case TDESC_TYPE_UNION:
- 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 ());
- gdb_printf
- (" tdesc_add_field (type_with_fields, \"%s\", field_type);\n",
- f.name.c_str ());
- }
- break;
- case TDESC_TYPE_ENUM:
- 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)
- gdb_printf
- (" tdesc_add_enum_value (type_with_fields, %d, \"%s\");\n",
- f.start, f.name.c_str ());
- break;
- default:
- error (_("C output is not supported type \"%s\"."), type->name.c_str ());
- }
- gdb_printf ("\n");
- }
- void visit (const tdesc_reg *reg) override
- {
- gdb_printf (" tdesc_create_reg (feature, \"%s\", %ld, %d, ",
- reg->name.c_str (), reg->target_regnum,
- reg->save_restore);
- if (!reg->group.empty ())
- gdb_printf ("\"%s\", ", reg->group.c_str ());
- else
- gdb_printf ("NULL, ");
- gdb_printf ("%d, \"%s\");\n", reg->bitsize, reg->type.c_str ());
- }
- protected:
- std::string m_filename_after_features;
- private:
- /* Print an assignment to the field_type variable. Print the declaration
- of field_type if that has not been done yet. */
- ATTRIBUTE_PRINTF (2, 3)
- void printf_field_type_assignment (const char *fmt, ...)
- {
- if (!m_printed_field_type)
- {
- gdb_printf (" tdesc_type *field_type;\n");
- m_printed_field_type = true;
- }
- gdb_printf (" field_type = ");
- va_list args;
- va_start (args, fmt);
- gdb_vprintf (fmt, args);
- va_end (args);
- }
- char *m_function;
- /* Did we print "struct tdesc_type *element_type;" yet? */
- bool m_printed_element_type = false;
- /* Did we print "struct tdesc_type_with_fields *element_type;" yet? */
- bool m_printed_type_with_fields = false;
- /* Did we print "struct tdesc_type *field_type;" yet? */
- bool m_printed_field_type = false;
- };
- /* Print target description feature in C. */
- class print_c_feature : public print_c_tdesc
- {
- public:
- print_c_feature (std::string &file)
- : print_c_tdesc (file)
- {
- /* Trim ".tmp". */
- auto const pos = m_filename_after_features.find_last_of ('.');
- m_filename_after_features = m_filename_after_features.substr (0, pos);
- }
- void visit_pre (const target_desc *e) override
- {
- gdb_printf (" Original: %s */\n\n",
- lbasename (m_filename_after_features.c_str ()));
- gdb_printf ("#include \"gdbsupport/tdesc.h\"\n");
- gdb_printf ("\n");
- }
- void visit_post (const target_desc *e) override
- {}
- void visit_pre (const tdesc_feature *e) override
- {
- std::string name (m_filename_after_features);
- auto pos = name.find_first_of ('.');
- name = name.substr (0, pos);
- std::replace (name.begin (), name.end (), '/', '_');
- std::replace (name.begin (), name.end (), '-', '_');
- gdb_printf ("static int\n");
- gdb_printf ("create_feature_%s ", name.c_str ());
- gdb_printf ("(struct target_desc *result, long regnum)\n");
- gdb_printf ("{\n");
- gdb_printf (" struct tdesc_feature *feature;\n");
- gdb_printf
- ("\n feature = tdesc_create_feature (result, \"%s\");\n",
- e->name.c_str ());
- }
- void visit_post (const tdesc_feature *e) override
- {
- gdb_printf (" return regnum;\n");
- gdb_printf ("}\n");
- }
- void visit (const tdesc_reg *reg) override
- {
- /* Most "reg" in XML target descriptions don't have "regnum"
- attribute, so the register number is allocated sequentially.
- In case that reg has "regnum" attribute, register number
- should be set by that explicitly. */
- if (reg->target_regnum < m_next_regnum)
- {
- /* The integrity check, it can catch some errors on register
- number collision, like this,
- <reg name="x0" bitsize="32"/>
- <reg name="x1" bitsize="32"/>
- <reg name="x2" bitsize="32"/>
- <reg name="x3" bitsize="32"/>
- <reg name="ps" bitsize="32" regnum="3"/>
- but it also has false negatives. The target description
- below is correct,
- <reg name="x1" bitsize="32" regnum="1"/>
- <reg name="x3" bitsize="32" regnum="3"/>
- <reg name="x2" bitsize="32" regnum="2"/>
- <reg name="x4" bitsize="32" regnum="4"/>
- but it is not a good practice, so still error on this,
- and also print the message so that it can be saved in the
- generated c file. */
- 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)
- {
- gdb_printf (" regnum = %ld;\n", reg->target_regnum);
- m_next_regnum = reg->target_regnum;
- }
- gdb_printf (" tdesc_create_reg (feature, \"%s\", regnum++, %d, ",
- reg->name.c_str (), reg->save_restore);
- if (!reg->group.empty ())
- gdb_printf ("\"%s\", ", reg->group.c_str ());
- else
- gdb_printf ("NULL, ");
- gdb_printf ("%d, \"%s\");\n", reg->bitsize, reg->type.c_str ());
- m_next_regnum++;
- }
- private:
- /* The register number to use for the next register we see. */
- int m_next_regnum = 0;
- };
- /* See gdbsupport/tdesc.h. */
- const char *
- tdesc_get_features_xml (const target_desc *tdesc)
- {
- if (tdesc->xmltarget == nullptr)
- {
- std::string buffer ("@");
- print_xml_feature v (&buffer);
- tdesc->accept (v);
- tdesc->xmltarget = xstrdup (buffer.c_str ());
- }
- 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<maint_print_c_tdesc_options>;
- 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. */
- target_desc_info *tdesc_info = get_tdesc_info (current_inferior ());
- tdesc = tdesc_info->tdesc;
- filename = tdesc_info->filename.data ();
- }
- else
- {
- /* Use the target description from the XML file. */
- filename = args;
- tdesc = file_read_description_xml (filename);
- }
- if (tdesc == NULL)
- error (_("There is no target description to print."));
- if (filename == NULL)
- filename = "fetched from target";
- std::string filename_after_features (filename);
- auto loc = filename_after_features.rfind ("/features/");
- if (loc != std::string::npos)
- filename_after_features = filename_after_features.substr (loc + 10);
- /* Print c files for target features instead of target descriptions,
- because c files got from target features are more flexible than the
- counterparts. */
- 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);
- }
- else
- {
- print_c_tdesc v (filename_after_features);
- tdesc->accept (v);
- }
- }
- /* 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). */
- struct xml_test_tdesc
- {
- xml_test_tdesc (const char *name, std::unique_ptr<const target_desc> &&tdesc)
- : name (name), tdesc (std::move (tdesc))
- {}
- const char *name;
- std::unique_ptr<const target_desc> tdesc;
- };
- static std::vector<xml_test_tdesc> xml_tdesc;
- #if GDB_SELF_TEST
- /* See target-descriptions.h. */
- void
- record_xml_tdesc (const char *xml_file, const struct target_desc *tdesc)
- {
- xml_tdesc.emplace_back (xml_file, std::unique_ptr<const target_desc> (tdesc));
- }
- #endif
- }
- /* Test the conversion process of a target description to/from xml: Take a target
- description TDESC, convert to xml, back to a description, and confirm the new
- tdesc is identical to the original. */
- static bool
- maintenance_check_tdesc_xml_convert (const target_desc *tdesc, const char *name)
- {
- const char *xml = tdesc_get_features_xml (tdesc);
- if (xml == nullptr || *xml != '@')
- {
- gdb_printf (_("Could not convert description for %s to xml.\n"),
- name);
- return false;
- }
- const target_desc *tdesc_trans = string_read_description_xml (xml + 1);
- if (tdesc_trans == nullptr)
- {
- gdb_printf (_("Could not convert description for %s from xml.\n"),
- name);
- return false;
- }
- else if (*tdesc != *tdesc_trans)
- {
- gdb_printf (_("Converted description for %s does not match.\n"),
- name);
- return false;
- }
- return true;
- }
- /* Check that the target descriptions created dynamically by
- architecture-specific code equal the descriptions created from XML files
- found in the specified directory DIR. */
- static void
- maintenance_check_xml_descriptions (const char *dir, int from_tty)
- {
- if (dir == NULL)
- error (_("Missing dir name"));
- gdb::unique_xmalloc_ptr<char> dir1 (tilde_expand (dir));
- std::string feature_dir (dir1.get ());
- unsigned int failed = 0;
- for (auto const &e : selftests::xml_tdesc)
- {
- std::string tdesc_xml = (feature_dir + SLASH_STRING + e.name);
- const target_desc *tdesc
- = file_read_description_xml (tdesc_xml.data ());
- if (tdesc == NULL || *tdesc != *e.tdesc)
- {
- 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++;
- }
- 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_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,
- 0 /* allow-unknown */, &unsetlist);
- add_setshow_filename_cmd ("filename", class_obscure,
- &tdesc_filename_cmd_string,
- _("\
- Set the file to read for an XML target description."), _("\
- Show the file to read for an XML target description."), _("\
- When set, GDB will read the target description from a local\n\
- file instead of querying the remote target."),
- set_tdesc_filename_cmd,
- show_tdesc_filename_cmd,
- &tdesc_set_cmdlist, &tdesc_show_cmdlist);
- add_cmd ("filename", class_obscure, unset_tdesc_filename_cmd, _("\
- Unset the file to read for an XML target description.\n\
- When unset, GDB will read the description from the target."),
- &tdesc_unset_cmdlist);
- 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, _("\
- Check equality of GDB target descriptions and XML created descriptions.\n\
- Check the target descriptions created in GDB equal the descriptions\n\
- created from XML files in the directory.\n\
- The parameter is the directory name."),
- &maintenancechecklist);
- set_cmd_completer (cmd, filename_completer);
- }
|