12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640 |
- /* Rust language support routines for GDB, the GNU debugger.
- Copyright (C) 2016-2022 Free Software Foundation, Inc.
- This file is part of GDB.
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License, or
- (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>. */
- #include "defs.h"
- #include <ctype.h>
- #include "block.h"
- #include "c-lang.h"
- #include "charset.h"
- #include "cp-support.h"
- #include "demangle.h"
- #include "gdbarch.h"
- #include "infcall.h"
- #include "objfiles.h"
- #include "psymtab.h"
- #include "rust-lang.h"
- #include "typeprint.h"
- #include "valprint.h"
- #include "varobj.h"
- #include <algorithm>
- #include <string>
- #include <vector>
- #include "cli/cli-style.h"
- #include "parser-defs.h"
- #include "rust-exp.h"
- /* See rust-lang.h. */
- const char *
- rust_last_path_segment (const char *path)
- {
- const char *result = strrchr (path, ':');
- if (result == NULL)
- return path;
- return result + 1;
- }
- /* See rust-lang.h. */
- std::string
- rust_crate_for_block (const struct block *block)
- {
- const char *scope = block_scope (block);
- if (scope[0] == '\0')
- return std::string ();
- return std::string (scope, cp_find_first_component (scope));
- }
- /* Return true if TYPE, which must be a struct type, represents a Rust
- enum. */
- static bool
- rust_enum_p (struct type *type)
- {
- /* is_dynamic_type will return true if any field has a dynamic
- attribute -- but we only want to check the top level. */
- return TYPE_HAS_VARIANT_PARTS (type);
- }
- /* Return true if TYPE, which must be an already-resolved enum type,
- has no variants. */
- static bool
- rust_empty_enum_p (const struct type *type)
- {
- return type->num_fields () == 0;
- }
- /* Given an already-resolved enum type and contents, find which
- variant is active. */
- static int
- rust_enum_variant (struct type *type)
- {
- /* The active variant is simply the first non-artificial field. */
- for (int i = 0; i < type->num_fields (); ++i)
- if (!TYPE_FIELD_ARTIFICIAL (type, i))
- return i;
- /* Perhaps we could get here by trying to print an Ada variant
- record in Rust mode. Unlikely, but an error is safer than an
- assert. */
- error (_("Could not find active enum variant"));
- }
- /* See rust-lang.h. */
- bool
- rust_tuple_type_p (struct type *type)
- {
- /* The current implementation is a bit of a hack, but there's
- nothing else in the debuginfo to distinguish a tuple from a
- struct. */
- return (type->code () == TYPE_CODE_STRUCT
- && type->name () != NULL
- && type->name ()[0] == '(');
- }
- /* Return true if all non-static fields of a structlike type are in a
- sequence like __0, __1, __2. */
- static bool
- rust_underscore_fields (struct type *type)
- {
- int i, field_number;
- field_number = 0;
- if (type->code () != TYPE_CODE_STRUCT)
- return false;
- for (i = 0; i < type->num_fields (); ++i)
- {
- if (!field_is_static (&type->field (i)))
- {
- char buf[20];
- xsnprintf (buf, sizeof (buf), "__%d", field_number);
- if (strcmp (buf, type->field (i).name ()) != 0)
- return false;
- field_number++;
- }
- }
- return true;
- }
- /* See rust-lang.h. */
- bool
- rust_tuple_struct_type_p (struct type *type)
- {
- /* This is just an approximation until DWARF can represent Rust more
- precisely. We exclude zero-length structs because they may not
- be tuple structs, and there's no way to tell. */
- return type->num_fields () > 0 && rust_underscore_fields (type);
- }
- /* Return true if TYPE is a slice type, otherwise false. */
- static bool
- rust_slice_type_p (struct type *type)
- {
- return (type->code () == TYPE_CODE_STRUCT
- && type->name () != NULL
- && (strncmp (type->name (), "&[", 2) == 0
- || strcmp (type->name (), "&str") == 0));
- }
- /* Return true if TYPE is a range type, otherwise false. */
- static bool
- rust_range_type_p (struct type *type)
- {
- int i;
- if (type->code () != TYPE_CODE_STRUCT
- || type->num_fields () > 2
- || type->name () == NULL
- || strstr (type->name (), "::Range") == NULL)
- return false;
- if (type->num_fields () == 0)
- return true;
- i = 0;
- if (strcmp (type->field (0).name (), "start") == 0)
- {
- if (type->num_fields () == 1)
- return true;
- i = 1;
- }
- else if (type->num_fields () == 2)
- {
- /* First field had to be "start". */
- return false;
- }
- return strcmp (type->field (i).name (), "end") == 0;
- }
- /* Return true if TYPE is an inclusive range type, otherwise false.
- This is only valid for types which are already known to be range
- types. */
- static bool
- rust_inclusive_range_type_p (struct type *type)
- {
- return (strstr (type->name (), "::RangeInclusive") != NULL
- || strstr (type->name (), "::RangeToInclusive") != NULL);
- }
- /* Return true if TYPE seems to be the type "u8", otherwise false. */
- static bool
- rust_u8_type_p (struct type *type)
- {
- return (type->code () == TYPE_CODE_INT
- && type->is_unsigned ()
- && TYPE_LENGTH (type) == 1);
- }
- /* Return true if TYPE is a Rust character type. */
- static bool
- rust_chartype_p (struct type *type)
- {
- return (type->code () == TYPE_CODE_CHAR
- && TYPE_LENGTH (type) == 4
- && type->is_unsigned ());
- }
- /* If VALUE represents a trait object pointer, return the underlying
- pointer with the correct (i.e., runtime) type. Otherwise, return
- NULL. */
- static struct value *
- rust_get_trait_object_pointer (struct value *value)
- {
- struct type *type = check_typedef (value_type (value));
- if (type->code () != TYPE_CODE_STRUCT || type->num_fields () != 2)
- return NULL;
- /* Try to be a bit resilient if the ABI changes. */
- int vtable_field = 0;
- for (int i = 0; i < 2; ++i)
- {
- if (strcmp (type->field (i).name (), "vtable") == 0)
- vtable_field = i;
- else if (strcmp (type->field (i).name (), "pointer") != 0)
- return NULL;
- }
- CORE_ADDR vtable = value_as_address (value_field (value, vtable_field));
- struct symbol *symbol = find_symbol_at_address (vtable);
- if (symbol == NULL || symbol->subclass != SYMBOL_RUST_VTABLE)
- return NULL;
- struct rust_vtable_symbol *vtable_sym
- = static_cast<struct rust_vtable_symbol *> (symbol);
- struct type *pointer_type = lookup_pointer_type (vtable_sym->concrete_type);
- return value_cast (pointer_type, value_field (value, 1 - vtable_field));
- }
- /* See language.h. */
- void
- rust_language::printstr (struct ui_file *stream, struct type *type,
- const gdb_byte *string, unsigned int length,
- const char *user_encoding, int force_ellipses,
- const struct value_print_options *options) const
- {
- /* Rust always uses UTF-8, but let the caller override this if need
- be. */
- const char *encoding = user_encoding;
- if (user_encoding == NULL || !*user_encoding)
- {
- /* In Rust strings, characters are "u8". */
- if (rust_u8_type_p (type))
- encoding = "UTF-8";
- else
- {
- /* This is probably some C string, so let's let C deal with
- it. */
- c_printstr (stream, type, string, length, user_encoding,
- force_ellipses, options);
- return;
- }
- }
- /* This is not ideal as it doesn't use our character printer. */
- generic_printstr (stream, type, string, length, encoding, force_ellipses,
- '"', 0, options);
- }
- /* Helper function to print a string slice. */
- static void
- rust_val_print_str (struct ui_file *stream, struct value *val,
- const struct value_print_options *options)
- {
- struct value *base = value_struct_elt (&val, {}, "data_ptr", NULL,
- "slice");
- struct value *len = value_struct_elt (&val, {}, "length", NULL, "slice");
- val_print_string (TYPE_TARGET_TYPE (value_type (base)), "UTF-8",
- value_as_address (base), value_as_long (len), stream,
- options);
- }
- /* See rust-lang.h. */
- void
- rust_language::val_print_struct
- (struct value *val, struct ui_file *stream, int recurse,
- const struct value_print_options *options) const
- {
- int i;
- int first_field;
- struct type *type = check_typedef (value_type (val));
- if (rust_slice_type_p (type) && strcmp (type->name (), "&str") == 0)
- {
- /* If what we are printing here is actually a string within a
- structure then VAL will be the original parent value, while TYPE
- will be the type of the structure representing the string we want
- to print.
- However, RUST_VAL_PRINT_STR looks up the fields of the string
- inside VAL, assuming that VAL is the string.
- So, recreate VAL as a value representing just the string. */
- val = value_at_lazy (type, value_address (val));
- rust_val_print_str (stream, val, options);
- return;
- }
- bool is_tuple = rust_tuple_type_p (type);
- bool is_tuple_struct = !is_tuple && rust_tuple_struct_type_p (type);
- struct value_print_options opts;
- if (!is_tuple)
- {
- if (type->name () != NULL)
- gdb_printf (stream, "%s", type->name ());
- if (type->num_fields () == 0)
- return;
- if (type->name () != NULL)
- gdb_puts (" ", stream);
- }
- if (is_tuple || is_tuple_struct)
- gdb_puts ("(", stream);
- else
- gdb_puts ("{", stream);
- opts = *options;
- opts.deref_ref = 0;
- first_field = 1;
- for (i = 0; i < type->num_fields (); ++i)
- {
- if (field_is_static (&type->field (i)))
- continue;
- if (!first_field)
- gdb_puts (",", stream);
- if (options->prettyformat)
- {
- gdb_puts ("\n", stream);
- print_spaces (2 + 2 * recurse, stream);
- }
- else if (!first_field)
- gdb_puts (" ", stream);
- first_field = 0;
- if (!is_tuple && !is_tuple_struct)
- {
- fputs_styled (type->field (i).name (),
- variable_name_style.style (), stream);
- gdb_puts (": ", stream);
- }
- common_val_print (value_field (val, i), stream, recurse + 1, &opts,
- this);
- }
- if (options->prettyformat)
- {
- gdb_puts ("\n", stream);
- print_spaces (2 * recurse, stream);
- }
- if (is_tuple || is_tuple_struct)
- gdb_puts (")", stream);
- else
- gdb_puts ("}", stream);
- }
- /* See rust-lang.h. */
- void
- rust_language::print_enum (struct value *val, struct ui_file *stream,
- int recurse,
- const struct value_print_options *options) const
- {
- struct value_print_options opts = *options;
- struct type *type = check_typedef (value_type (val));
- opts.deref_ref = 0;
- gdb_assert (rust_enum_p (type));
- gdb::array_view<const gdb_byte> view
- (value_contents_for_printing (val).data (),
- TYPE_LENGTH (value_type (val)));
- type = resolve_dynamic_type (type, view, value_address (val));
- if (rust_empty_enum_p (type))
- {
- /* Print the enum type name here to be more clear. */
- gdb_printf (stream, _("%s {%p[<No data fields>%p]}"),
- type->name (),
- metadata_style.style ().ptr (), nullptr);
- return;
- }
- int variant_fieldno = rust_enum_variant (type);
- val = value_field (val, variant_fieldno);
- struct type *variant_type = type->field (variant_fieldno).type ();
- int nfields = variant_type->num_fields ();
- bool is_tuple = rust_tuple_struct_type_p (variant_type);
- gdb_printf (stream, "%s", variant_type->name ());
- if (nfields == 0)
- {
- /* In case of a nullary variant like 'None', just output
- the name. */
- return;
- }
- /* In case of a non-nullary variant, we output 'Foo(x,y,z)'. */
- if (is_tuple)
- gdb_printf (stream, "(");
- else
- {
- /* struct variant. */
- gdb_printf (stream, "{");
- }
- bool first_field = true;
- for (int j = 0; j < variant_type->num_fields (); j++)
- {
- if (!first_field)
- gdb_puts (", ", stream);
- first_field = false;
- if (!is_tuple)
- gdb_printf (stream, "%ps: ",
- styled_string (variable_name_style.style (),
- variant_type->field (j).name ()));
- common_val_print (value_field (val, j), stream, recurse + 1, &opts,
- this);
- }
- if (is_tuple)
- gdb_puts (")", stream);
- else
- gdb_puts ("}", stream);
- }
- static const struct generic_val_print_decorations rust_decorations =
- {
- /* Complex isn't used in Rust, but we provide C-ish values just in
- case. */
- "",
- " + ",
- " * I",
- "true",
- "false",
- "()",
- "[",
- "]"
- };
- /* See language.h. */
- void
- rust_language::value_print_inner
- (struct value *val, struct ui_file *stream, int recurse,
- const struct value_print_options *options) const
- {
- struct value_print_options opts = *options;
- opts.deref_ref = 1;
- if (opts.prettyformat == Val_prettyformat_default)
- opts.prettyformat = (opts.prettyformat_structs
- ? Val_prettyformat : Val_no_prettyformat);
- struct type *type = check_typedef (value_type (val));
- switch (type->code ())
- {
- case TYPE_CODE_PTR:
- {
- LONGEST low_bound, high_bound;
-
- if (TYPE_TARGET_TYPE (type)->code () == TYPE_CODE_ARRAY
- && rust_u8_type_p (TYPE_TARGET_TYPE (TYPE_TARGET_TYPE (type)))
- && get_array_bounds (TYPE_TARGET_TYPE (type), &low_bound,
- &high_bound))
- {
- /* We have a pointer to a byte string, so just print
- that. */
- struct type *elttype = check_typedef (TYPE_TARGET_TYPE (type));
- CORE_ADDR addr = value_as_address (val);
- struct gdbarch *arch = type->arch ();
- if (opts.addressprint)
- {
- gdb_puts (paddress (arch, addr), stream);
- gdb_puts (" ", stream);
- }
- gdb_puts ("b", stream);
- val_print_string (TYPE_TARGET_TYPE (elttype), "ASCII", addr,
- high_bound - low_bound + 1, stream,
- &opts);
- break;
- }
- }
- goto generic_print;
- case TYPE_CODE_INT:
- /* Recognize the unit type. */
- if (type->is_unsigned () && TYPE_LENGTH (type) == 0
- && type->name () != NULL && strcmp (type->name (), "()") == 0)
- {
- gdb_puts ("()", stream);
- break;
- }
- goto generic_print;
- case TYPE_CODE_STRING:
- {
- LONGEST low_bound, high_bound;
- if (!get_array_bounds (type, &low_bound, &high_bound))
- error (_("Could not determine the array bounds"));
- /* If we see a plain TYPE_CODE_STRING, then we're printing a
- byte string, hence the choice of "ASCII" as the
- encoding. */
- gdb_puts ("b", stream);
- printstr (stream, TYPE_TARGET_TYPE (type),
- value_contents_for_printing (val).data (),
- high_bound - low_bound + 1, "ASCII", 0, &opts);
- }
- break;
- case TYPE_CODE_ARRAY:
- {
- LONGEST low_bound, high_bound;
- if (get_array_bounds (type, &low_bound, &high_bound)
- && high_bound - low_bound + 1 == 0)
- gdb_puts ("[]", stream);
- else
- goto generic_print;
- }
- break;
- case TYPE_CODE_UNION:
- /* Untagged unions are printed as if they are structs. Since
- the field bit positions overlap in the debuginfo, the code
- for printing a union is same as that for a struct, the only
- difference is that the input type will have overlapping
- fields. */
- val_print_struct (val, stream, recurse, &opts);
- break;
- case TYPE_CODE_STRUCT:
- if (rust_enum_p (type))
- print_enum (val, stream, recurse, &opts);
- else
- val_print_struct (val, stream, recurse, &opts);
- break;
- default:
- generic_print:
- /* Nothing special yet. */
- generic_value_print (val, stream, recurse, &opts, &rust_decorations);
- }
- }
- static void
- rust_internal_print_type (struct type *type, const char *varstring,
- struct ui_file *stream, int show, int level,
- const struct type_print_options *flags,
- bool for_rust_enum, print_offset_data *podata);
- /* Print a struct or union typedef. */
- static void
- rust_print_struct_def (struct type *type, const char *varstring,
- struct ui_file *stream, int show, int level,
- const struct type_print_options *flags,
- bool for_rust_enum, print_offset_data *podata)
- {
- /* Print a tuple type simply. */
- if (rust_tuple_type_p (type))
- {
- gdb_puts (type->name (), stream);
- return;
- }
- /* If we see a base class, delegate to C. */
- if (TYPE_N_BASECLASSES (type) > 0)
- c_print_type (type, varstring, stream, show, level, flags);
- if (flags->print_offsets)
- {
- /* Temporarily bump the level so that the output lines up
- correctly. */
- level += 2;
- }
- /* Compute properties of TYPE here because, in the enum case, the
- rest of the code ends up looking only at the variant part. */
- const char *tagname = type->name ();
- bool is_tuple_struct = rust_tuple_struct_type_p (type);
- bool is_tuple = rust_tuple_type_p (type);
- bool is_enum = rust_enum_p (type);
- if (for_rust_enum)
- {
- /* Already printing an outer enum, so nothing to print here. */
- }
- else
- {
- /* This code path is also used by unions and enums. */
- if (is_enum)
- {
- gdb_puts ("enum ", stream);
- dynamic_prop *prop = type->dyn_prop (DYN_PROP_VARIANT_PARTS);
- if (prop != nullptr && prop->kind () == PROP_TYPE)
- type = prop->original_type ();
- }
- else if (type->code () == TYPE_CODE_STRUCT)
- gdb_puts ("struct ", stream);
- else
- gdb_puts ("union ", stream);
- if (tagname != NULL)
- gdb_puts (tagname, stream);
- }
- if (type->num_fields () == 0 && !is_tuple)
- return;
- if (for_rust_enum && !flags->print_offsets)
- gdb_puts (is_tuple_struct ? "(" : "{", stream);
- else
- gdb_puts (is_tuple_struct ? " (\n" : " {\n", stream);
- /* When printing offsets, we rearrange the fields into storage
- order. This lets us show holes more clearly. We work using
- field indices here because it simplifies calls to
- print_offset_data::update below. */
- std::vector<int> fields;
- for (int i = 0; i < type->num_fields (); ++i)
- {
- if (field_is_static (&type->field (i)))
- continue;
- if (is_enum && TYPE_FIELD_ARTIFICIAL (type, i))
- continue;
- fields.push_back (i);
- }
- if (flags->print_offsets)
- std::sort (fields.begin (), fields.end (),
- [&] (int a, int b)
- {
- return (type->field (a).loc_bitpos ()
- < type->field (b).loc_bitpos ());
- });
- for (int i : fields)
- {
- QUIT;
- gdb_assert (!field_is_static (&type->field (i)));
- gdb_assert (! (is_enum && TYPE_FIELD_ARTIFICIAL (type, i)));
- if (flags->print_offsets)
- podata->update (type, i, stream);
- /* We'd like to print "pub" here as needed, but rustc
- doesn't emit the debuginfo, and our types don't have
- cplus_struct_type attached. */
- /* For a tuple struct we print the type but nothing
- else. */
- if (!for_rust_enum || flags->print_offsets)
- print_spaces (level + 2, stream);
- if (is_enum)
- fputs_styled (type->field (i).name (), variable_name_style.style (),
- stream);
- else if (!is_tuple_struct)
- gdb_printf (stream, "%ps: ",
- styled_string (variable_name_style.style (),
- type->field (i).name ()));
- rust_internal_print_type (type->field (i).type (), NULL,
- stream, (is_enum ? show : show - 1),
- level + 2, flags, is_enum, podata);
- if (!for_rust_enum || flags->print_offsets)
- gdb_puts (",\n", stream);
- /* Note that this check of "I" is ok because we only sorted the
- fields by offset when print_offsets was set, so we won't take
- this branch in that case. */
- else if (i + 1 < type->num_fields ())
- gdb_puts (", ", stream);
- }
- if (flags->print_offsets)
- {
- /* Undo the temporary level increase we did above. */
- level -= 2;
- podata->finish (type, level, stream);
- print_spaces (print_offset_data::indentation, stream);
- if (level == 0)
- print_spaces (2, stream);
- }
- if (!for_rust_enum || flags->print_offsets)
- print_spaces (level, stream);
- gdb_puts (is_tuple_struct ? ")" : "}", stream);
- }
- /* la_print_type implementation for Rust. */
- static void
- rust_internal_print_type (struct type *type, const char *varstring,
- struct ui_file *stream, int show, int level,
- const struct type_print_options *flags,
- bool for_rust_enum, print_offset_data *podata)
- {
- QUIT;
- if (show <= 0
- && type->name () != NULL)
- {
- /* Rust calls the unit type "void" in its debuginfo,
- but we don't want to print it as that. */
- if (type->code () == TYPE_CODE_VOID)
- gdb_puts ("()", stream);
- else
- gdb_puts (type->name (), stream);
- return;
- }
- type = check_typedef (type);
- switch (type->code ())
- {
- case TYPE_CODE_VOID:
- /* If we have an enum, we've already printed the type's
- unqualified name, and there is nothing else to print
- here. */
- if (!for_rust_enum)
- gdb_puts ("()", stream);
- break;
- case TYPE_CODE_FUNC:
- /* Delegate varargs to the C printer. */
- if (type->has_varargs ())
- goto c_printer;
- gdb_puts ("fn ", stream);
- if (varstring != NULL)
- gdb_puts (varstring, stream);
- gdb_puts ("(", stream);
- for (int i = 0; i < type->num_fields (); ++i)
- {
- QUIT;
- if (i > 0)
- gdb_puts (", ", stream);
- rust_internal_print_type (type->field (i).type (), "", stream,
- -1, 0, flags, false, podata);
- }
- gdb_puts (")", stream);
- /* If it returns unit, we can omit the return type. */
- if (TYPE_TARGET_TYPE (type)->code () != TYPE_CODE_VOID)
- {
- gdb_puts (" -> ", stream);
- rust_internal_print_type (TYPE_TARGET_TYPE (type), "", stream,
- -1, 0, flags, false, podata);
- }
- break;
- case TYPE_CODE_ARRAY:
- {
- LONGEST low_bound, high_bound;
- gdb_puts ("[", stream);
- rust_internal_print_type (TYPE_TARGET_TYPE (type), NULL,
- stream, show - 1, level, flags, false,
- podata);
- if (type->bounds ()->high.kind () == PROP_LOCEXPR
- || type->bounds ()->high.kind () == PROP_LOCLIST)
- gdb_printf (stream, "; variable length");
- else if (get_array_bounds (type, &low_bound, &high_bound))
- gdb_printf (stream, "; %s",
- plongest (high_bound - low_bound + 1));
- gdb_puts ("]", stream);
- }
- break;
- case TYPE_CODE_UNION:
- case TYPE_CODE_STRUCT:
- rust_print_struct_def (type, varstring, stream, show, level, flags,
- for_rust_enum, podata);
- break;
- case TYPE_CODE_ENUM:
- {
- int len = 0;
- gdb_puts ("enum ", stream);
- if (type->name () != NULL)
- {
- gdb_puts (type->name (), stream);
- gdb_puts (" ", stream);
- len = strlen (type->name ());
- }
- gdb_puts ("{\n", stream);
- for (int i = 0; i < type->num_fields (); ++i)
- {
- const char *name = type->field (i).name ();
- QUIT;
- if (len > 0
- && strncmp (name, type->name (), len) == 0
- && name[len] == ':'
- && name[len + 1] == ':')
- name += len + 2;
- gdb_printf (stream, "%*s%ps,\n",
- level + 2, "",
- styled_string (variable_name_style.style (),
- name));
- }
- gdb_puts ("}", stream);
- }
- break;
- case TYPE_CODE_PTR:
- {
- if (type->name () != nullptr)
- gdb_puts (type->name (), stream);
- else
- {
- /* We currently can't distinguish between pointers and
- references. */
- gdb_puts ("*mut ", stream);
- type_print (TYPE_TARGET_TYPE (type), "", stream, 0);
- }
- }
- break;
- default:
- c_printer:
- c_print_type (type, varstring, stream, show, level, flags);
- }
- }
- /* Like arch_composite_type, but uses TYPE to decide how to allocate
- -- either on an obstack or on a gdbarch. */
- static struct type *
- rust_composite_type (struct type *original,
- const char *name,
- const char *field1, struct type *type1,
- const char *field2, struct type *type2)
- {
- struct type *result = alloc_type_copy (original);
- int i, nfields, bitpos;
- nfields = 0;
- if (field1 != NULL)
- ++nfields;
- if (field2 != NULL)
- ++nfields;
- result->set_code (TYPE_CODE_STRUCT);
- result->set_name (name);
- result->set_num_fields (nfields);
- result->set_fields
- ((struct field *) TYPE_ZALLOC (result, nfields * sizeof (struct field)));
- i = 0;
- bitpos = 0;
- if (field1 != NULL)
- {
- struct field *field = &result->field (i);
- field->set_loc_bitpos (bitpos);
- bitpos += TYPE_LENGTH (type1) * TARGET_CHAR_BIT;
- field->set_name (field1);
- field->set_type (type1);
- ++i;
- }
- if (field2 != NULL)
- {
- struct field *field = &result->field (i);
- unsigned align = type_align (type2);
- if (align != 0)
- {
- int delta;
- align *= TARGET_CHAR_BIT;
- delta = bitpos % align;
- if (delta != 0)
- bitpos += align - delta;
- }
- field->set_loc_bitpos (bitpos);
- field->set_name (field2);
- field->set_type (type2);
- ++i;
- }
- if (i > 0)
- TYPE_LENGTH (result)
- = (result->field (i - 1).loc_bitpos () / TARGET_CHAR_BIT +
- TYPE_LENGTH (result->field (i - 1).type ()));
- return result;
- }
- /* See rust-lang.h. */
- struct type *
- rust_slice_type (const char *name, struct type *elt_type,
- struct type *usize_type)
- {
- struct type *type;
- elt_type = lookup_pointer_type (elt_type);
- type = rust_composite_type (elt_type, name,
- "data_ptr", elt_type,
- "length", usize_type);
- return type;
- }
- /* A helper for rust_evaluate_subexp that handles OP_RANGE. */
- struct value *
- rust_range (struct type *expect_type, struct expression *exp,
- enum noside noside, enum range_flag kind,
- struct value *low, struct value *high)
- {
- struct value *addrval, *result;
- CORE_ADDR addr;
- struct type *range_type;
- struct type *index_type;
- struct type *temp_type;
- const char *name;
- bool inclusive = !(kind & RANGE_HIGH_BOUND_EXCLUSIVE);
- if (low == NULL)
- {
- if (high == NULL)
- {
- index_type = NULL;
- name = "std::ops::RangeFull";
- }
- else
- {
- index_type = value_type (high);
- name = (inclusive
- ? "std::ops::RangeToInclusive" : "std::ops::RangeTo");
- }
- }
- else
- {
- if (high == NULL)
- {
- index_type = value_type (low);
- name = "std::ops::RangeFrom";
- }
- else
- {
- if (!types_equal (value_type (low), value_type (high)))
- error (_("Range expression with different types"));
- index_type = value_type (low);
- name = inclusive ? "std::ops::RangeInclusive" : "std::ops::Range";
- }
- }
- /* If we don't have an index type, just allocate this on the
- arch. Here any type will do. */
- temp_type = (index_type == NULL
- ? language_bool_type (exp->language_defn, exp->gdbarch)
- : index_type);
- /* It would be nicer to cache the range type. */
- range_type = rust_composite_type (temp_type, name,
- low == NULL ? NULL : "start", index_type,
- high == NULL ? NULL : "end", index_type);
- if (noside == EVAL_AVOID_SIDE_EFFECTS)
- return value_zero (range_type, lval_memory);
- addrval = value_allocate_space_in_inferior (TYPE_LENGTH (range_type));
- addr = value_as_long (addrval);
- result = value_at_lazy (range_type, addr);
- if (low != NULL)
- {
- struct value *start = value_struct_elt (&result, {}, "start", NULL,
- "range");
- value_assign (start, low);
- }
- if (high != NULL)
- {
- struct value *end = value_struct_elt (&result, {}, "end", NULL,
- "range");
- value_assign (end, high);
- }
- result = value_at_lazy (range_type, addr);
- return result;
- }
- /* A helper function to compute the range and kind given a range
- value. TYPE is the type of the range value. RANGE is the range
- value. LOW, HIGH, and KIND are out parameters. The LOW and HIGH
- parameters might be filled in, or might not be, depending on the
- kind of range this is. KIND will always be set to the appropriate
- value describing the kind of range, and this can be used to
- determine whether LOW or HIGH are valid. */
- static void
- rust_compute_range (struct type *type, struct value *range,
- LONGEST *low, LONGEST *high,
- range_flags *kind)
- {
- int i;
- *low = 0;
- *high = 0;
- *kind = RANGE_LOW_BOUND_DEFAULT | RANGE_HIGH_BOUND_DEFAULT;
- if (type->num_fields () == 0)
- return;
- i = 0;
- if (strcmp (type->field (0).name (), "start") == 0)
- {
- *kind = RANGE_HIGH_BOUND_DEFAULT;
- *low = value_as_long (value_field (range, 0));
- ++i;
- }
- if (type->num_fields () > i
- && strcmp (type->field (i).name (), "end") == 0)
- {
- *kind = (*kind == (RANGE_LOW_BOUND_DEFAULT | RANGE_HIGH_BOUND_DEFAULT)
- ? RANGE_LOW_BOUND_DEFAULT : RANGE_STANDARD);
- *high = value_as_long (value_field (range, i));
- if (rust_inclusive_range_type_p (type))
- ++*high;
- }
- }
- /* A helper for rust_evaluate_subexp that handles BINOP_SUBSCRIPT. */
- struct value *
- rust_subscript (struct type *expect_type, struct expression *exp,
- enum noside noside, bool for_addr,
- struct value *lhs, struct value *rhs)
- {
- struct value *result;
- struct type *rhstype;
- LONGEST low, high_bound;
- /* Initialized to appease the compiler. */
- range_flags kind = RANGE_LOW_BOUND_DEFAULT | RANGE_HIGH_BOUND_DEFAULT;
- LONGEST high = 0;
- int want_slice = 0;
- rhstype = check_typedef (value_type (rhs));
- if (rust_range_type_p (rhstype))
- {
- if (!for_addr)
- error (_("Can't take slice of array without '&'"));
- rust_compute_range (rhstype, rhs, &low, &high, &kind);
- want_slice = 1;
- }
- else
- low = value_as_long (rhs);
- struct type *type = check_typedef (value_type (lhs));
- if (noside == EVAL_AVOID_SIDE_EFFECTS)
- {
- struct type *base_type = nullptr;
- if (type->code () == TYPE_CODE_ARRAY)
- base_type = TYPE_TARGET_TYPE (type);
- else if (rust_slice_type_p (type))
- {
- for (int i = 0; i < type->num_fields (); ++i)
- {
- if (strcmp (type->field (i).name (), "data_ptr") == 0)
- {
- base_type = TYPE_TARGET_TYPE (type->field (i).type ());
- break;
- }
- }
- if (base_type == nullptr)
- error (_("Could not find 'data_ptr' in slice type"));
- }
- else if (type->code () == TYPE_CODE_PTR)
- base_type = TYPE_TARGET_TYPE (type);
- else
- error (_("Cannot subscript non-array type"));
- struct type *new_type;
- if (want_slice)
- {
- if (rust_slice_type_p (type))
- new_type = type;
- else
- {
- struct type *usize
- = language_lookup_primitive_type (exp->language_defn,
- exp->gdbarch,
- "usize");
- new_type = rust_slice_type ("&[*gdb*]", base_type, usize);
- }
- }
- else
- new_type = base_type;
- return value_zero (new_type, VALUE_LVAL (lhs));
- }
- else
- {
- LONGEST low_bound;
- struct value *base;
- if (type->code () == TYPE_CODE_ARRAY)
- {
- base = lhs;
- if (!get_array_bounds (type, &low_bound, &high_bound))
- error (_("Can't compute array bounds"));
- if (low_bound != 0)
- error (_("Found array with non-zero lower bound"));
- ++high_bound;
- }
- else if (rust_slice_type_p (type))
- {
- struct value *len;
- base = value_struct_elt (&lhs, {}, "data_ptr", NULL, "slice");
- len = value_struct_elt (&lhs, {}, "length", NULL, "slice");
- low_bound = 0;
- high_bound = value_as_long (len);
- }
- else if (type->code () == TYPE_CODE_PTR)
- {
- base = lhs;
- low_bound = 0;
- high_bound = LONGEST_MAX;
- }
- else
- error (_("Cannot subscript non-array type"));
- if (want_slice && (kind & RANGE_LOW_BOUND_DEFAULT))
- low = low_bound;
- if (low < 0)
- error (_("Index less than zero"));
- if (low > high_bound)
- error (_("Index greater than length"));
- result = value_subscript (base, low);
- }
- if (for_addr)
- {
- if (want_slice)
- {
- struct type *usize, *slice;
- CORE_ADDR addr;
- struct value *addrval, *tem;
- if (kind & RANGE_HIGH_BOUND_DEFAULT)
- high = high_bound;
- if (high < 0)
- error (_("High index less than zero"));
- if (low > high)
- error (_("Low index greater than high index"));
- if (high > high_bound)
- error (_("High index greater than length"));
- usize = language_lookup_primitive_type (exp->language_defn,
- exp->gdbarch,
- "usize");
- const char *new_name = ((type != nullptr
- && rust_slice_type_p (type))
- ? type->name () : "&[*gdb*]");
- slice = rust_slice_type (new_name, value_type (result), usize);
- addrval = value_allocate_space_in_inferior (TYPE_LENGTH (slice));
- addr = value_as_long (addrval);
- tem = value_at_lazy (slice, addr);
- value_assign (value_field (tem, 0), value_addr (result));
- value_assign (value_field (tem, 1),
- value_from_longest (usize, high - low));
- result = value_at_lazy (slice, addr);
- }
- else
- result = value_addr (result);
- }
- return result;
- }
- namespace expr
- {
- struct value *
- rust_unop_ind_operation::evaluate (struct type *expect_type,
- struct expression *exp,
- enum noside noside)
- {
- if (noside != EVAL_NORMAL)
- return unop_ind_operation::evaluate (expect_type, exp, noside);
- struct value *value = std::get<0> (m_storage)->evaluate (nullptr, exp,
- noside);
- struct value *trait_ptr = rust_get_trait_object_pointer (value);
- if (trait_ptr != NULL)
- value = trait_ptr;
- return value_ind (value);
- }
- } /* namespace expr */
- /* A helper function for UNOP_COMPLEMENT. */
- struct value *
- eval_op_rust_complement (struct type *expect_type, struct expression *exp,
- enum noside noside,
- enum exp_opcode opcode,
- struct value *value)
- {
- if (value_type (value)->code () == TYPE_CODE_BOOL)
- return value_from_longest (value_type (value), value_logical_not (value));
- return value_complement (value);
- }
- /* A helper function for OP_ARRAY. */
- struct value *
- eval_op_rust_array (struct type *expect_type, struct expression *exp,
- enum noside noside,
- enum exp_opcode opcode,
- struct value *elt, struct value *ncopies)
- {
- int copies = value_as_long (ncopies);
- if (copies < 0)
- error (_("Array with negative number of elements"));
- if (noside == EVAL_NORMAL)
- {
- int i;
- std::vector<struct value *> eltvec (copies);
- for (i = 0; i < copies; ++i)
- eltvec[i] = elt;
- return value_array (0, copies - 1, eltvec.data ());
- }
- else
- {
- struct type *arraytype
- = lookup_array_range_type (value_type (elt), 0, copies - 1);
- return allocate_value (arraytype);
- }
- }
- namespace expr
- {
- struct value *
- rust_struct_anon::evaluate (struct type *expect_type,
- struct expression *exp,
- enum noside noside)
- {
- value *lhs = std::get<1> (m_storage)->evaluate (nullptr, exp, noside);
- int field_number = std::get<0> (m_storage);
- struct type *type = value_type (lhs);
- if (type->code () == TYPE_CODE_STRUCT)
- {
- struct type *outer_type = NULL;
- if (rust_enum_p (type))
- {
- type = resolve_dynamic_type (type, value_contents (lhs),
- value_address (lhs));
- if (rust_empty_enum_p (type))
- error (_("Cannot access field %d of empty enum %s"),
- field_number, type->name ());
- int fieldno = rust_enum_variant (type);
- lhs = value_primitive_field (lhs, 0, fieldno, type);
- outer_type = type;
- type = value_type (lhs);
- }
- /* Tuples and tuple structs */
- int nfields = type->num_fields ();
- if (field_number >= nfields || field_number < 0)
- {
- if (outer_type != NULL)
- error(_("Cannot access field %d of variant %s::%s, "
- "there are only %d fields"),
- field_number, outer_type->name (),
- rust_last_path_segment (type->name ()),
- nfields);
- else
- error(_("Cannot access field %d of %s, "
- "there are only %d fields"),
- field_number, type->name (), nfields);
- }
- /* Tuples are tuple structs too. */
- if (!rust_tuple_struct_type_p (type))
- {
- if (outer_type != NULL)
- error(_("Variant %s::%s is not a tuple variant"),
- outer_type->name (),
- rust_last_path_segment (type->name ()));
- else
- error(_("Attempting to access anonymous field %d "
- "of %s, which is not a tuple, tuple struct, or "
- "tuple-like variant"),
- field_number, type->name ());
- }
- return value_primitive_field (lhs, 0, field_number, type);
- }
- else
- error(_("Anonymous field access is only allowed on tuples, \
- tuple structs, and tuple-like enum variants"));
- }
- struct value *
- rust_structop::evaluate (struct type *expect_type,
- struct expression *exp,
- enum noside noside)
- {
- value *lhs = std::get<0> (m_storage)->evaluate (nullptr, exp, noside);
- const char *field_name = std::get<1> (m_storage).c_str ();
- struct value *result;
- struct type *type = value_type (lhs);
- if (type->code () == TYPE_CODE_STRUCT && rust_enum_p (type))
- {
- type = resolve_dynamic_type (type, value_contents (lhs),
- value_address (lhs));
- if (rust_empty_enum_p (type))
- error (_("Cannot access field %s of empty enum %s"),
- field_name, type->name ());
- int fieldno = rust_enum_variant (type);
- lhs = value_primitive_field (lhs, 0, fieldno, type);
- struct type *outer_type = type;
- type = value_type (lhs);
- if (rust_tuple_type_p (type) || rust_tuple_struct_type_p (type))
- error (_("Attempting to access named field %s of tuple "
- "variant %s::%s, which has only anonymous fields"),
- field_name, outer_type->name (),
- rust_last_path_segment (type->name ()));
- try
- {
- result = value_struct_elt (&lhs, {}, field_name,
- NULL, "structure");
- }
- catch (const gdb_exception_error &except)
- {
- error (_("Could not find field %s of struct variant %s::%s"),
- field_name, outer_type->name (),
- rust_last_path_segment (type->name ()));
- }
- }
- else
- result = value_struct_elt (&lhs, {}, field_name, NULL, "structure");
- if (noside == EVAL_AVOID_SIDE_EFFECTS)
- result = value_zero (value_type (result), VALUE_LVAL (result));
- return result;
- }
- value *
- rust_aggregate_operation::evaluate (struct type *expect_type,
- struct expression *exp,
- enum noside noside)
- {
- struct type *type = std::get<0> (m_storage);
- CORE_ADDR addr = 0;
- struct value *addrval = NULL;
- value *result;
- if (noside == EVAL_NORMAL)
- {
- addrval = value_allocate_space_in_inferior (TYPE_LENGTH (type));
- addr = value_as_long (addrval);
- result = value_at_lazy (type, addr);
- }
- if (std::get<1> (m_storage) != nullptr)
- {
- struct value *init = std::get<1> (m_storage)->evaluate (nullptr, exp,
- noside);
- if (noside == EVAL_NORMAL)
- {
- /* This isn't quite right but will do for the time
- being, seeing that we can't implement the Copy
- trait anyway. */
- value_assign (result, init);
- }
- }
- for (const auto &item : std::get<2> (m_storage))
- {
- value *val = item.second->evaluate (nullptr, exp, noside);
- if (noside == EVAL_NORMAL)
- {
- const char *fieldname = item.first.c_str ();
- value *field = value_struct_elt (&result, {}, fieldname,
- nullptr, "structure");
- value_assign (field, val);
- }
- }
- if (noside == EVAL_AVOID_SIDE_EFFECTS)
- result = allocate_value (type);
- else
- result = value_at_lazy (type, addr);
- return result;
- }
- value *
- rust_structop::evaluate_funcall (struct type *expect_type,
- struct expression *exp,
- enum noside noside,
- const std::vector<operation_up> &ops)
- {
- std::vector<struct value *> args (ops.size () + 1);
- /* Evaluate the argument to STRUCTOP_STRUCT, then find its
- type in order to look up the method. */
- args[0] = std::get<0> (m_storage)->evaluate (nullptr, exp, noside);
- /* We don't yet implement real Deref semantics. */
- while (value_type (args[0])->code () == TYPE_CODE_PTR)
- args[0] = value_ind (args[0]);
- struct type *type = value_type (args[0]);
- if ((type->code () != TYPE_CODE_STRUCT
- && type->code () != TYPE_CODE_UNION
- && type->code () != TYPE_CODE_ENUM)
- || rust_tuple_type_p (type))
- error (_("Method calls only supported on struct or enum types"));
- if (type->name () == NULL)
- error (_("Method call on nameless type"));
- std::string name = (std::string (type->name ()) + "::"
- + std::get<1> (m_storage));
- const struct block *block = get_selected_block (0);
- struct block_symbol sym = lookup_symbol (name.c_str (), block,
- VAR_DOMAIN, NULL);
- if (sym.symbol == NULL)
- error (_("Could not find function named '%s'"), name.c_str ());
- struct type *fn_type = sym.symbol->type ();
- if (fn_type->num_fields () == 0)
- error (_("Function '%s' takes no arguments"), name.c_str ());
- if (fn_type->field (0).type ()->code () == TYPE_CODE_PTR)
- args[0] = value_addr (args[0]);
- value *function = address_of_variable (sym.symbol, block);
- for (int i = 0; i < ops.size (); ++i)
- args[i + 1] = ops[i]->evaluate (nullptr, exp, noside);
- if (noside == EVAL_AVOID_SIDE_EFFECTS)
- return value_zero (TYPE_TARGET_TYPE (fn_type), not_lval);
- return call_function_by_hand (function, NULL, args);
- }
- }
- /* See language.h. */
- void
- rust_language::language_arch_info (struct gdbarch *gdbarch,
- struct language_arch_info *lai) const
- {
- const struct builtin_type *builtin = builtin_type (gdbarch);
- /* Helper function to allow shorter lines below. */
- auto add = [&] (struct type * t) -> struct type *
- {
- lai->add_primitive_type (t);
- return t;
- };
- struct type *bool_type
- = add (arch_boolean_type (gdbarch, 8, 1, "bool"));
- add (arch_character_type (gdbarch, 32, 1, "char"));
- add (arch_integer_type (gdbarch, 8, 0, "i8"));
- struct type *u8_type
- = add (arch_integer_type (gdbarch, 8, 1, "u8"));
- add (arch_integer_type (gdbarch, 16, 0, "i16"));
- add (arch_integer_type (gdbarch, 16, 1, "u16"));
- add (arch_integer_type (gdbarch, 32, 0, "i32"));
- add (arch_integer_type (gdbarch, 32, 1, "u32"));
- add (arch_integer_type (gdbarch, 64, 0, "i64"));
- add (arch_integer_type (gdbarch, 64, 1, "u64"));
- unsigned int length = 8 * TYPE_LENGTH (builtin->builtin_data_ptr);
- add (arch_integer_type (gdbarch, length, 0, "isize"));
- struct type *usize_type
- = add (arch_integer_type (gdbarch, length, 1, "usize"));
- add (arch_float_type (gdbarch, 32, "f32", floatformats_ieee_single));
- add (arch_float_type (gdbarch, 64, "f64", floatformats_ieee_double));
- add (arch_integer_type (gdbarch, 0, 1, "()"));
- struct type *tem = make_cv_type (1, 0, u8_type, NULL);
- add (rust_slice_type ("&str", tem, usize_type));
- lai->set_bool_type (bool_type);
- lai->set_string_char_type (u8_type);
- }
- /* See language.h. */
- void
- rust_language::print_type (struct type *type, const char *varstring,
- struct ui_file *stream, int show, int level,
- const struct type_print_options *flags) const
- {
- print_offset_data podata (flags);
- rust_internal_print_type (type, varstring, stream, show, level,
- flags, false, &podata);
- }
- /* See language.h. */
- void
- rust_language::emitchar (int ch, struct type *chtype,
- struct ui_file *stream, int quoter) const
- {
- if (!rust_chartype_p (chtype))
- generic_emit_char (ch, chtype, stream, quoter,
- target_charset (chtype->arch ()));
- else if (ch == '\\' || ch == quoter)
- gdb_printf (stream, "\\%c", ch);
- else if (ch == '\n')
- gdb_puts ("\\n", stream);
- else if (ch == '\r')
- gdb_puts ("\\r", stream);
- else if (ch == '\t')
- gdb_puts ("\\t", stream);
- else if (ch == '\0')
- gdb_puts ("\\0", stream);
- else if (ch >= 32 && ch <= 127 && isprint (ch))
- gdb_putc (ch, stream);
- else if (ch <= 255)
- gdb_printf (stream, "\\x%02x", ch);
- else
- gdb_printf (stream, "\\u{%06x}", ch);
- }
- /* See language.h. */
- bool
- rust_language::is_string_type_p (struct type *type) const
- {
- LONGEST low_bound, high_bound;
- type = check_typedef (type);
- return ((type->code () == TYPE_CODE_STRING)
- || (type->code () == TYPE_CODE_PTR
- && (TYPE_TARGET_TYPE (type)->code () == TYPE_CODE_ARRAY
- && rust_u8_type_p (TYPE_TARGET_TYPE (TYPE_TARGET_TYPE (type)))
- && get_array_bounds (TYPE_TARGET_TYPE (type), &low_bound,
- &high_bound)))
- || (type->code () == TYPE_CODE_STRUCT
- && !rust_enum_p (type)
- && rust_slice_type_p (type)
- && strcmp (type->name (), "&str") == 0));
- }
- /* Single instance of the Rust language class. */
- static rust_language rust_language_defn;
|