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