Home | History | Annotate | Line # | Download | only in guile
      1 /* Scheme interface to lazy strings.
      2 
      3    Copyright (C) 2010-2024 Free Software Foundation, Inc.
      4 
      5    This file is part of GDB.
      6 
      7    This program is free software; you can redistribute it and/or modify
      8    it under the terms of the GNU General Public License as published by
      9    the Free Software Foundation; either version 3 of the License, or
     10    (at your option) any later version.
     11 
     12    This program is distributed in the hope that it will be useful,
     13    but WITHOUT ANY WARRANTY; without even the implied warranty of
     14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     15    GNU General Public License for more details.
     16 
     17    You should have received a copy of the GNU General Public License
     18    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
     19 
     20 /* See README file in this directory for implementation notes, coding
     21    conventions, et.al.  */
     22 
     23 #include "charset.h"
     24 #include "value.h"
     25 #include "valprint.h"
     26 #include "language.h"
     27 #include "guile-internal.h"
     28 
     29 /* The <gdb:lazy-string> smob.  */
     30 
     31 struct lazy_string_smob
     32 {
     33   /* This always appears first.  */
     34   gdb_smob base;
     35 
     36   /*  Holds the address of the lazy string.  */
     37   CORE_ADDR address;
     38 
     39   /*  Holds the encoding that will be applied to the string when the string
     40       is printed by GDB.  If the encoding is set to NULL then GDB will select
     41       the most appropriate encoding when the sting is printed.
     42       Space for this is malloc'd and will be freed when the object is
     43       freed.  */
     44   char *encoding;
     45 
     46   /* If TYPE is an array: If the length is known, then this value is the
     47      array's length, otherwise it is -1.
     48      If TYPE is not an array: Then this value represents the string's length.
     49      In either case, if the value is -1 then the string will be fetched and
     50      encoded up to the first null of appropriate width.  */
     51   int length;
     52 
     53   /* The type of the string.
     54      For example if the lazy string was created from a C "char*" then TYPE
     55      represents a C "char*".  To get the type of the character in the string
     56      call lsscm_elt_type which handles the different kinds of values for TYPE.
     57      This is recorded as an SCM object so that we take advantage of support for
     58      preserving the type should its owning objfile go away.  */
     59   SCM type;
     60 };
     61 
     62 static const char lazy_string_smob_name[] = "gdb:lazy-string";
     63 
     64 /* The tag Guile knows the lazy string smob by.  */
     65 static scm_t_bits lazy_string_smob_tag;
     66 
     67 /* Administrivia for lazy string smobs.  */
     69 
     70 /* The smob "free" function for <gdb:lazy-string>.  */
     71 
     72 static size_t
     73 lsscm_free_lazy_string_smob (SCM self)
     74 {
     75   lazy_string_smob *v_smob = (lazy_string_smob *) SCM_SMOB_DATA (self);
     76 
     77   xfree (v_smob->encoding);
     78 
     79   return 0;
     80 }
     81 
     82 /* The smob "print" function for <gdb:lazy-string>.  */
     83 
     84 static int
     85 lsscm_print_lazy_string_smob (SCM self, SCM port, scm_print_state *pstate)
     86 {
     87   lazy_string_smob *ls_smob = (lazy_string_smob *) SCM_SMOB_DATA (self);
     88 
     89   gdbscm_printf (port, "#<%s", lazy_string_smob_name);
     90   gdbscm_printf (port, " @%s", hex_string (ls_smob->address));
     91   if (ls_smob->length >= 0)
     92     gdbscm_printf (port, " length %d", ls_smob->length);
     93   if (ls_smob->encoding != NULL)
     94     gdbscm_printf (port, " encoding %s", ls_smob->encoding);
     95   scm_puts (">", port);
     96 
     97   scm_remember_upto_here_1 (self);
     98 
     99   /* Non-zero means success.  */
    100   return 1;
    101 }
    102 
    103 /* Low level routine to create a <gdb:lazy-string> object.
    104    The caller must verify:
    105    - length >= -1
    106    - !(address == 0 && length != 0)
    107    - type != NULL */
    108 
    109 static SCM
    110 lsscm_make_lazy_string_smob (CORE_ADDR address, int length,
    111 			     const char *encoding, struct type *type)
    112 {
    113   lazy_string_smob *ls_smob = (lazy_string_smob *)
    114     scm_gc_malloc (sizeof (lazy_string_smob), lazy_string_smob_name);
    115   SCM ls_scm;
    116 
    117   gdb_assert (length >= -1);
    118   gdb_assert (!(address == 0 && length != 0));
    119   gdb_assert (type != NULL);
    120 
    121   ls_smob->address = address;
    122   ls_smob->length = length;
    123   if (encoding == NULL || strcmp (encoding, "") == 0)
    124     ls_smob->encoding = NULL;
    125   else
    126     ls_smob->encoding = xstrdup (encoding);
    127   ls_smob->type = tyscm_scm_from_type (type);
    128 
    129   ls_scm = scm_new_smob (lazy_string_smob_tag, (scm_t_bits) ls_smob);
    130   gdbscm_init_gsmob (&ls_smob->base);
    131 
    132   return ls_scm;
    133 }
    134 
    135 /* Return non-zero if SCM is a <gdb:lazy-string> object.  */
    136 
    137 int
    138 lsscm_is_lazy_string (SCM scm)
    139 {
    140   return SCM_SMOB_PREDICATE (lazy_string_smob_tag, scm);
    141 }
    142 
    143 /* (lazy-string? object) -> boolean */
    144 
    145 static SCM
    146 gdbscm_lazy_string_p (SCM scm)
    147 {
    148   return scm_from_bool (lsscm_is_lazy_string (scm));
    149 }
    150 
    151 /* Main entry point to create a <gdb:lazy-string> object.
    152    If there's an error a <gdb:exception> object is returned.  */
    153 
    154 SCM
    155 lsscm_make_lazy_string (CORE_ADDR address, int length,
    156 			const char *encoding, struct type *type)
    157 {
    158   if (length < -1)
    159     {
    160       return gdbscm_make_out_of_range_error (NULL, 0,
    161 					     scm_from_int (length),
    162 					     _("invalid length"));
    163     }
    164 
    165   if (address == 0 && length != 0)
    166     {
    167       return gdbscm_make_out_of_range_error
    168 	(NULL, 0, scm_from_int (length),
    169 	 _("cannot create a lazy string with address 0x0,"
    170 	   " and a non-zero length"));
    171     }
    172 
    173   if (type == NULL)
    174     {
    175       return gdbscm_make_out_of_range_error
    176 	(NULL, 0, scm_from_int (0), _("a lazy string's type cannot be NULL"));
    177     }
    178 
    179   return lsscm_make_lazy_string_smob (address, length, encoding, type);
    180 }
    181 
    182 /* Returns the <gdb:lazy-string> smob in SELF.
    183    Throws an exception if SELF is not a <gdb:lazy-string> object.  */
    184 
    185 static SCM
    186 lsscm_get_lazy_string_arg_unsafe (SCM self, int arg_pos, const char *func_name)
    187 {
    188   SCM_ASSERT_TYPE (lsscm_is_lazy_string (self), self, arg_pos, func_name,
    189 		   lazy_string_smob_name);
    190 
    191   return self;
    192 }
    193 
    194 /* Return the type of a character in lazy string LS_SMOB.  */
    195 
    196 static struct type *
    197 lsscm_elt_type (lazy_string_smob *ls_smob)
    198 {
    199   struct type *type = tyscm_scm_to_type (ls_smob->type);
    200   struct type *realtype;
    201 
    202   realtype = check_typedef (type);
    203 
    204   switch (realtype->code ())
    205     {
    206     case TYPE_CODE_PTR:
    207     case TYPE_CODE_ARRAY:
    208       return realtype->target_type ();
    209     default:
    210       /* This is done to preserve existing behaviour.  PR 20769.
    211 	 E.g., gdb.parse_and_eval("my_int_variable").lazy_string().type.  */
    212       return realtype;
    213     }
    214 }
    215 
    216 /* Lazy string methods.  */
    218 
    219 /* (lazy-string-address <gdb:lazy-string>) -> address */
    220 
    221 static SCM
    222 gdbscm_lazy_string_address (SCM self)
    223 {
    224   SCM ls_scm = lsscm_get_lazy_string_arg_unsafe (self, SCM_ARG1, FUNC_NAME);
    225   lazy_string_smob *ls_smob = (lazy_string_smob *) SCM_SMOB_DATA (ls_scm);
    226 
    227   return gdbscm_scm_from_ulongest (ls_smob->address);
    228 }
    229 
    230 /* (lazy-string-length <gdb:lazy-string>) -> integer */
    231 
    232 static SCM
    233 gdbscm_lazy_string_length (SCM self)
    234 {
    235   SCM ls_scm = lsscm_get_lazy_string_arg_unsafe (self, SCM_ARG1, FUNC_NAME);
    236   lazy_string_smob *ls_smob = (lazy_string_smob *) SCM_SMOB_DATA (ls_scm);
    237 
    238   return scm_from_int (ls_smob->length);
    239 }
    240 
    241 /* (lazy-string-encoding <gdb:lazy-string>) -> string */
    242 
    243 static SCM
    244 gdbscm_lazy_string_encoding (SCM self)
    245 {
    246   SCM ls_scm = lsscm_get_lazy_string_arg_unsafe (self, SCM_ARG1, FUNC_NAME);
    247   lazy_string_smob *ls_smob = (lazy_string_smob *) SCM_SMOB_DATA (ls_scm);
    248 
    249   /* An encoding can be set to NULL by the user, so check first.
    250      If NULL return #f.  */
    251   if (ls_smob != NULL)
    252     return gdbscm_scm_from_c_string (ls_smob->encoding);
    253   return SCM_BOOL_F;
    254 }
    255 
    256 /* (lazy-string-type <gdb:lazy-string>) -> <gdb:type> */
    257 
    258 static SCM
    259 gdbscm_lazy_string_type (SCM self)
    260 {
    261   SCM ls_scm = lsscm_get_lazy_string_arg_unsafe (self, SCM_ARG1, FUNC_NAME);
    262   lazy_string_smob *ls_smob = (lazy_string_smob *) SCM_SMOB_DATA (ls_scm);
    263 
    264   return ls_smob->type;
    265 }
    266 
    267 /* (lazy-string->value <gdb:lazy-string>) -> <gdb:value> */
    268 
    269 static SCM
    270 gdbscm_lazy_string_to_value (SCM self)
    271 {
    272   SCM ls_scm = lsscm_get_lazy_string_arg_unsafe (self, SCM_ARG1, FUNC_NAME);
    273   SCM except_scm;
    274   struct value *value;
    275 
    276   value = lsscm_safe_lazy_string_to_value (ls_scm, SCM_ARG1, FUNC_NAME,
    277 					   &except_scm);
    278   if (value == NULL)
    279     gdbscm_throw (except_scm);
    280   return vlscm_scm_from_value (value);
    281 }
    282 
    283 /* A "safe" version of gdbscm_lazy_string_to_value for use by
    284    vlscm_convert_typed_value_from_scheme.
    285    The result, upon success, is the value of <gdb:lazy-string> STRING.
    286    ARG_POS is the argument position of STRING in the original Scheme
    287    function call, used in exception text.
    288    If there's an error, NULL is returned and a <gdb:exception> object
    289    is stored in *except_scmp.
    290 
    291    Note: The result is still "lazy".  The caller must call value_fetch_lazy
    292    to actually fetch the value.  */
    293 
    294 struct value *
    295 lsscm_safe_lazy_string_to_value (SCM string, int arg_pos,
    296 				 const char *func_name, SCM *except_scmp)
    297 {
    298   lazy_string_smob *ls_smob;
    299   struct value *value = NULL;
    300 
    301   gdb_assert (lsscm_is_lazy_string (string));
    302 
    303   ls_smob = (lazy_string_smob *) SCM_SMOB_DATA (string);
    304 
    305   if (ls_smob->address == 0)
    306     {
    307       *except_scmp
    308 	= gdbscm_make_out_of_range_error (func_name, arg_pos, string,
    309 					 _("cannot create a value from NULL"));
    310       return NULL;
    311     }
    312 
    313   try
    314     {
    315       struct type *type = tyscm_scm_to_type (ls_smob->type);
    316       struct type *realtype = check_typedef (type);
    317 
    318       switch (realtype->code ())
    319 	{
    320 	case TYPE_CODE_PTR:
    321 	  /* If a length is specified we need to convert this to an array
    322 	     of the specified size.  */
    323 	  if (ls_smob->length != -1)
    324 	    {
    325 	      /* PR 20786: There's no way to specify an array of length zero.
    326 		 Record a length of [0,-1] which is how Ada does it.  Anything
    327 		 we do is broken, but this one possible solution.  */
    328 	      type = lookup_array_range_type (realtype->target_type (),
    329 					      0, ls_smob->length - 1);
    330 	      value = value_at_lazy (type, ls_smob->address);
    331 	    }
    332 	  else
    333 	    value = value_from_pointer (type, ls_smob->address);
    334 	  break;
    335 	default:
    336 	  value = value_at_lazy (type, ls_smob->address);
    337 	  break;
    338 	}
    339     }
    340   catch (const gdb_exception &except)
    341     {
    342       *except_scmp = gdbscm_scm_from_gdb_exception (unpack (except));
    343       return NULL;
    344     }
    345 
    346   return value;
    347 }
    348 
    349 /* Print a lazy string to STREAM using val_print_string.
    350    STRING must be a <gdb:lazy-string> object.  */
    351 
    352 void
    353 lsscm_val_print_lazy_string (SCM string, struct ui_file *stream,
    354 			     const struct value_print_options *options)
    355 {
    356   lazy_string_smob *ls_smob;
    357   struct type *elt_type;
    358 
    359   gdb_assert (lsscm_is_lazy_string (string));
    360 
    361   ls_smob = (lazy_string_smob *) SCM_SMOB_DATA (string);
    362   elt_type = lsscm_elt_type (ls_smob);
    363 
    364   val_print_string (elt_type, ls_smob->encoding,
    365 		    ls_smob->address, ls_smob->length,
    366 		    stream, options);
    367 }
    368 
    369 /* Initialize the Scheme lazy-strings code.  */
    371 
    372 static const scheme_function lazy_string_functions[] =
    373 {
    374   { "lazy-string?", 1, 0, 0, as_a_scm_t_subr (gdbscm_lazy_string_p),
    375     "\
    376 Return #t if the object is a <gdb:lazy-string> object." },
    377 
    378   { "lazy-string-address", 1, 0, 0,
    379     as_a_scm_t_subr (gdbscm_lazy_string_address),
    380     "\
    381 Return the address of the lazy-string." },
    382 
    383   { "lazy-string-length", 1, 0, 0, as_a_scm_t_subr (gdbscm_lazy_string_length),
    384     "\
    385 Return the length of the lazy-string.\n\
    386 If the length is -1 then the length is determined by the first null\n\
    387 of appropriate width." },
    388 
    389   { "lazy-string-encoding", 1, 0, 0,
    390     as_a_scm_t_subr (gdbscm_lazy_string_encoding),
    391     "\
    392 Return the encoding of the lazy-string." },
    393 
    394   { "lazy-string-type", 1, 0, 0, as_a_scm_t_subr (gdbscm_lazy_string_type),
    395     "\
    396 Return the <gdb:type> of the lazy-string." },
    397 
    398   { "lazy-string->value", 1, 0, 0,
    399     as_a_scm_t_subr (gdbscm_lazy_string_to_value),
    400     "\
    401 Return the <gdb:value> representation of the lazy-string." },
    402 
    403   END_FUNCTIONS
    404 };
    405 
    406 void
    407 gdbscm_initialize_lazy_strings (void)
    408 {
    409   lazy_string_smob_tag = gdbscm_make_smob_type (lazy_string_smob_name,
    410 						sizeof (lazy_string_smob));
    411   scm_set_smob_free (lazy_string_smob_tag, lsscm_free_lazy_string_smob);
    412   scm_set_smob_print (lazy_string_smob_tag, lsscm_print_lazy_string_smob);
    413 
    414   gdbscm_define_functions (lazy_string_functions, 1);
    415 }
    416