xref: /netbsd-src/external/gpl3/gdb.old/dist/gdb/python/py-lazy-string.c (revision 8b657b0747480f8989760d71343d6dd33f8d4cf9)
1 /* Python interface to lazy strings.
2 
3    Copyright (C) 2010-2023 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 #include "defs.h"
21 #include "python-internal.h"
22 #include "charset.h"
23 #include "value.h"
24 #include "valprint.h"
25 #include "language.h"
26 
27 struct lazy_string_object {
28   PyObject_HEAD
29 
30   /*  Holds the address of the lazy string.  */
31   CORE_ADDR address;
32 
33   /*  Holds the encoding that will be applied to the string
34       when the string is printed by GDB.  If the encoding is set
35       to None then GDB will select the most appropriate
36       encoding when the sting is printed.  */
37   char *encoding;
38 
39   /* If TYPE is an array: If the length is known, then this value is the
40      array's length, otherwise it is -1.
41      If TYPE is not an array: Then this value represents the string's length.
42      In either case, if the value is -1 then the string will be fetched and
43      encoded up to the first null of appropriate width.  */
44   long length;
45 
46   /* This attribute holds the type of the string.
47      For example if the lazy string was created from a C "char*" then TYPE
48      represents a C "char*".
49      To get the type of the character in the string call
50      stpy_lazy_string_elt_type.
51      This is recorded as a PyObject so that we take advantage of support for
52      preserving the type should its owning objfile go away.  */
53   PyObject *type;
54 };
55 
56 extern PyTypeObject lazy_string_object_type
57     CPYCHECKER_TYPE_OBJECT_FOR_TYPEDEF ("lazy_string_object");
58 
59 static PyObject *
60 stpy_get_address (PyObject *self, void *closure)
61 {
62   lazy_string_object *self_string = (lazy_string_object *) self;
63 
64   return gdb_py_object_from_ulongest (self_string->address).release ();
65 }
66 
67 static PyObject *
68 stpy_get_encoding (PyObject *self, void *closure)
69 {
70   lazy_string_object *self_string = (lazy_string_object *) self;
71   PyObject *result;
72 
73   /* An encoding can be set to NULL by the user, so check before
74      attempting a Python FromString call.  If NULL return Py_None.  */
75   if (self_string->encoding)
76     result = PyUnicode_FromString (self_string->encoding);
77   else
78     {
79       result = Py_None;
80       Py_INCREF (result);
81     }
82 
83   return result;
84 }
85 
86 static PyObject *
87 stpy_get_length (PyObject *self, void *closure)
88 {
89   lazy_string_object *self_string = (lazy_string_object *) self;
90 
91   return gdb_py_object_from_longest (self_string->length).release ();
92 }
93 
94 static PyObject *
95 stpy_get_type (PyObject *self, void *closure)
96 {
97   lazy_string_object *str_obj = (lazy_string_object *) self;
98 
99   Py_INCREF (str_obj->type);
100   return str_obj->type;
101 }
102 
103 static PyObject *
104 stpy_convert_to_value (PyObject *self, PyObject *args)
105 {
106   lazy_string_object *self_string = (lazy_string_object *) self;
107   struct value *val = NULL;
108 
109   if (self_string->address == 0)
110     {
111       PyErr_SetString (gdbpy_gdb_memory_error,
112 		       _("Cannot create a value from NULL."));
113       return NULL;
114     }
115 
116   try
117     {
118       struct type *type = type_object_to_type (self_string->type);
119       struct type *realtype;
120 
121       gdb_assert (type != NULL);
122       realtype = check_typedef (type);
123       switch (realtype->code ())
124 	{
125 	case TYPE_CODE_PTR:
126 	  /* If a length is specified we need to convert this to an array
127 	     of the specified size.  */
128 	  if (self_string->length != -1)
129 	    {
130 	      /* PR 20786: There's no way to specify an array of length zero.
131 		 Record a length of [0,-1] which is how Ada does it.  Anything
132 		 we do is broken, but this is one possible solution.  */
133 	      type = lookup_array_range_type (realtype->target_type (),
134 					      0, self_string->length - 1);
135 	      val = value_at_lazy (type, self_string->address);
136 	    }
137 	  else
138 	    val = value_from_pointer (type, self_string->address);
139 	  break;
140 	default:
141 	  val = value_at_lazy (type, self_string->address);
142 	  break;
143 	}
144     }
145   catch (const gdb_exception &except)
146     {
147       GDB_PY_HANDLE_EXCEPTION (except);
148     }
149 
150   return value_to_value_object (val);
151 }
152 
153 static void
154 stpy_dealloc (PyObject *self)
155 {
156   lazy_string_object *self_string = (lazy_string_object *) self;
157 
158   xfree (self_string->encoding);
159   Py_TYPE (self)->tp_free (self);
160 }
161 
162 /* Low level routine to create a <gdb.LazyString> object.
163 
164    Note: If TYPE is an array, LENGTH either must be -1 (meaning to use the
165    size of the array, which may itself be unknown in which case a length of
166    -1 is still used) or must be the length of the array.  */
167 
168 PyObject *
169 gdbpy_create_lazy_string_object (CORE_ADDR address, long length,
170 				 const char *encoding, struct type *type)
171 {
172   lazy_string_object *str_obj = NULL;
173   struct type *realtype;
174 
175   if (length < -1)
176     {
177       PyErr_SetString (PyExc_ValueError, _("Invalid length."));
178       return NULL;
179     }
180 
181   if (address == 0 && length != 0)
182     {
183       PyErr_SetString (gdbpy_gdb_memory_error,
184 		       _("Cannot create a lazy string with address 0x0, " \
185 			 "and a non-zero length."));
186       return NULL;
187     }
188 
189   if (!type)
190     {
191       PyErr_SetString (PyExc_RuntimeError,
192 		       _("A lazy string's type cannot be NULL."));
193       return NULL;
194     }
195 
196   realtype = check_typedef (type);
197   switch (realtype->code ())
198     {
199     case TYPE_CODE_ARRAY:
200       {
201 	LONGEST array_length = -1;
202 	LONGEST low_bound, high_bound;
203 
204 	if (get_array_bounds (realtype, &low_bound, &high_bound))
205 	  array_length = high_bound - low_bound + 1;
206 	if (length == -1)
207 	  length = array_length;
208 	else if (length != array_length)
209 	  {
210 	    PyErr_SetString (PyExc_ValueError, _("Invalid length."));
211 	    return NULL;
212 	  }
213 	break;
214       }
215     }
216 
217   str_obj = PyObject_New (lazy_string_object, &lazy_string_object_type);
218   if (!str_obj)
219     return NULL;
220 
221   str_obj->address = address;
222   str_obj->length = length;
223   if (encoding == NULL || !strcmp (encoding, ""))
224     str_obj->encoding = NULL;
225   else
226     str_obj->encoding = xstrdup (encoding);
227   str_obj->type = type_to_type_object (type);
228 
229   return (PyObject *) str_obj;
230 }
231 
232 int
233 gdbpy_initialize_lazy_string (void)
234 {
235   if (PyType_Ready (&lazy_string_object_type) < 0)
236     return -1;
237 
238   Py_INCREF (&lazy_string_object_type);
239   return 0;
240 }
241 
242 /* Determine whether the printer object pointed to by OBJ is a
243    Python lazy string.  */
244 int
245 gdbpy_is_lazy_string (PyObject *result)
246 {
247   return PyObject_TypeCheck (result, &lazy_string_object_type);
248 }
249 
250 /* Return the type of a character in lazy string LAZY.  */
251 
252 static struct type *
253 stpy_lazy_string_elt_type (lazy_string_object *lazy)
254 {
255   struct type *type = type_object_to_type (lazy->type);
256   struct type *realtype;
257 
258   gdb_assert (type != NULL);
259   realtype = check_typedef (type);
260 
261   switch (realtype->code ())
262     {
263     case TYPE_CODE_PTR:
264     case TYPE_CODE_ARRAY:
265       return realtype->target_type ();
266     default:
267       /* This is done to preserve existing behaviour.  PR 20769.
268 	 E.g., gdb.parse_and_eval("my_int_variable").lazy_string().type.  */
269       return realtype;
270     }
271 }
272 
273 /* Extract the parameters from the lazy string object STRING.
274    ENCODING may be set to NULL, if no encoding is found.  */
275 
276 void
277 gdbpy_extract_lazy_string (PyObject *string, CORE_ADDR *addr,
278 			   struct type **str_elt_type,
279 			   long *length,
280 			   gdb::unique_xmalloc_ptr<char> *encoding)
281 {
282   lazy_string_object *lazy;
283 
284   gdb_assert (gdbpy_is_lazy_string (string));
285 
286   lazy = (lazy_string_object *) string;
287 
288   *addr = lazy->address;
289   *str_elt_type = stpy_lazy_string_elt_type (lazy);
290   *length = lazy->length;
291   encoding->reset (lazy->encoding ? xstrdup (lazy->encoding) : NULL);
292 }
293 
294 
295 
296 static PyMethodDef lazy_string_object_methods[] = {
297   { "value", stpy_convert_to_value, METH_NOARGS,
298     "Create a (lazy) value that contains a pointer to the string." },
299   {NULL}  /* Sentinel */
300 };
301 
302 
303 static gdb_PyGetSetDef lazy_string_object_getset[] = {
304   { "address", stpy_get_address, NULL, "Address of the string.", NULL },
305   { "encoding", stpy_get_encoding, NULL, "Encoding of the string.", NULL },
306   { "length", stpy_get_length, NULL, "Length of the string.", NULL },
307   { "type", stpy_get_type, NULL, "Type associated with the string.", NULL },
308   { NULL }  /* Sentinel */
309 };
310 
311 PyTypeObject lazy_string_object_type = {
312   PyVarObject_HEAD_INIT (NULL, 0)
313   "gdb.LazyString",	          /*tp_name*/
314   sizeof (lazy_string_object),	  /*tp_basicsize*/
315   0,				  /*tp_itemsize*/
316   stpy_dealloc,                   /*tp_dealloc*/
317   0,				  /*tp_print*/
318   0,				  /*tp_getattr*/
319   0,				  /*tp_setattr*/
320   0,				  /*tp_compare*/
321   0,				  /*tp_repr*/
322   0,				  /*tp_as_number*/
323   0,				  /*tp_as_sequence*/
324   0,				  /*tp_as_mapping*/
325   0,				  /*tp_hash */
326   0,				  /*tp_call*/
327   0,				  /*tp_str*/
328   0,				  /*tp_getattro*/
329   0,				  /*tp_setattro*/
330   0,				  /*tp_as_buffer*/
331   Py_TPFLAGS_DEFAULT,             /*tp_flags*/
332   "GDB lazy string object",	  /* tp_doc */
333   0,				  /* tp_traverse */
334   0,				  /* tp_clear */
335   0,				  /* tp_richcompare */
336   0,				  /* tp_weaklistoffset */
337   0,			          /* tp_iter */
338   0,				  /* tp_iternext */
339   lazy_string_object_methods,	  /* tp_methods */
340   0,				  /* tp_members */
341   lazy_string_object_getset	  /* tp_getset */
342 };
343