diff options
author | Phil Muldoon <pmuldoon@redhat.com> | 2010-01-14 08:03:37 +0000 |
---|---|---|
committer | Phil Muldoon <pmuldoon@redhat.com> | 2010-01-14 08:03:37 +0000 |
commit | be759fcf73cbf7ac59863c57389cd97c70c09a47 (patch) | |
tree | f3261b3c2096f57e5a2e09242ecc82a2cc7acb8b /gdb/python | |
parent | 009f105539b0fedd36d9d1de940a3822372ed818 (diff) | |
download | gdb-be759fcf73cbf7ac59863c57389cd97c70c09a47.zip gdb-be759fcf73cbf7ac59863c57389cd97c70c09a47.tar.gz gdb-be759fcf73cbf7ac59863c57389cd97c70c09a47.tar.bz2 |
2010-01-13 Phil Muldoon <pmuldoon@redhat.com>
PR python/10705
* python/python-internal.h: Add lazy_string_object_type
definition.
(create_lazy_string_object, gdbpy_initialize_lazy_string)
(gdbpy_is_lazystring, gdbpy_extract_lazy_string): Define.
* python/py-value.c (valpy_lazy_string): New function.
(convert_value_from_python): Add lazy string conversion.
* python/py-prettyprint.c (pretty_print_one_value): Check if
return is also a lazy string.
(print_string_repr): Add lazy string printing branch.
(print_children): Likewise.
* python/py-lazy-string.c: New file. Implement lazy strings.
* python/python.c (_initialize_python): Call
gdbpy_initialize_lazy_string.
* varobj.c (value_get_print_value): Add lazy string printing
branch. Account for encoding.
* c-lang.c (c_printstr): Account for new encoding argument. If
encoding is NULL, find encoding suited for type, otherwise use
user encoding.
* language.h (language_defn): Add encoding argument.
(LA_PRINT_STRING): Likewise.
* language.c (unk_lang_printstr): Update to reflect new encoding
argument to language_defn.
* ada-lang.h (ada_printstr): Likewise.
* c-lang.h (c_printstr): Likewise.
* p-lang.h (pascal_printstr);
* f-lang.c (f_printstr): Likewise.
* m2-lang.c (m2_printstr): Likewise.
* objc-lang.c (objc_printstr): Likewise.
* p-lang.c (pascal_printstr): Likewise.
* scm-lang.c (scm_printstr): Likewise.
* c-valprint.c (c_val_print): Update LA_PRINT_STRING call for
encoding argument.
* ada-valprint.c (ada_printstr): Likewise.
* f-valprint.c (f_val_print): Likewise
* m2-valprint.c (m2_val_print): Likewise.
* p-valprint.c (pascal_val_print): Likewise.
* expprint.c (print_subexp_standard): Likewise.
* valprint.c (val_print_string): Likewise.
* Makefile.in (SUBDIR_PYTHON_OBS): Add py-lazy-string.
(SUBDIR_PYTHON_SRCS): Likewise.
(py-lazy-string.o): New rule.
2010-01-13 Phil Muldoon <pmuldoon@redhat.com>
* gdb.texinfo (Values From Inferior): Document lazy_string value
method.
(Python API): Add Lazy strings menu item.
(Lazy Strings In Python): New node.
2010-01-13 Phil Muldoon <pmuldoon@redhat.com>
* gdb.python/py-value.exp (test_lazy_strings): Add lazy string test.
* gdb.python/py-prettyprint.py (pp_ls): New printer.
* gdb.python/py-prettyprint.exp (run_lang_tests): Add lazy string
test.
* gdb.python/py-prettyprint.c: Define lazystring test structure.
* gdb.python/py-mi.exp: Add lazy string test.
Diffstat (limited to 'gdb/python')
-rw-r--r-- | gdb/python/py-lazy-string.c | 291 | ||||
-rw-r--r-- | gdb/python/py-prettyprint.c | 73 | ||||
-rw-r--r-- | gdb/python/py-value.c | 40 | ||||
-rw-r--r-- | gdb/python/python-internal.h | 7 | ||||
-rw-r--r-- | gdb/python/python.c | 1 |
5 files changed, 397 insertions, 15 deletions
diff --git a/gdb/python/py-lazy-string.c b/gdb/python/py-lazy-string.c new file mode 100644 index 0000000..c845273 --- /dev/null +++ b/gdb/python/py-lazy-string.c @@ -0,0 +1,291 @@ +/* Python interface to lazy strings. + + Copyright (C) 2010 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 "python-internal.h" +#include "charset.h" +#include "value.h" +#include "exceptions.h" +#include "valprint.h" +#include "language.h" + +typedef struct { + PyObject_HEAD + /* Holds the address of the lazy string. */ + CORE_ADDR address; + + /* Holds the encoding that will be applied to the string + when the string is printed by GDB. If the encoding is set + to None then GDB will select the most appropriate + encoding when the sting is printed. */ + char *encoding; + + /* Holds the length of the string in characters. If the + length is -1, then the string will be fetched and encoded up to + the first null of appropriate width. */ + long length; + + /* This attribute holds the type that is represented by the lazy + string's type. */ + struct type *type; +} lazy_string_object; + +static PyTypeObject lazy_string_object_type; + +static PyObject * +stpy_get_address (PyObject *self, void *closure) +{ + lazy_string_object *self_string = (lazy_string_object *) self; + return PyLong_FromUnsignedLongLong (self_string->address); +} + +static PyObject * +stpy_get_encoding (PyObject *self, void *closure) +{ + lazy_string_object *self_string = (lazy_string_object *) self; + PyObject *result; + + /* An encoding can be set to NULL by the user, so check before + attempting a Python FromString call. If NULL return Py_None. */ + if (self_string->encoding) + result = PyString_FromString (self_string->encoding); + else + { + result = Py_None; + Py_INCREF (result); + } + + return result; +} + +static PyObject * +stpy_get_length (PyObject *self, void *closure) +{ + lazy_string_object *self_string = (lazy_string_object *) self; + return PyLong_FromLong (self_string->length); +} + +PyObject * +stpy_get_type (PyObject *self, void *closure) +{ + lazy_string_object *str_obj = (lazy_string_object *) self; + return type_to_type_object (str_obj->type); +} + +static PyObject * +stpy_convert_to_value (PyObject *self, PyObject *args) +{ + lazy_string_object *self_string = (lazy_string_object *) self; + struct value *val; + + val = value_at_lazy (self_string->type, self_string->address); + return value_to_value_object (val); +} + +static void +stpy_dealloc (PyObject *self) +{ + lazy_string_object *self_string = (lazy_string_object *) self; + xfree (self_string->encoding); +} + +PyObject * +gdbpy_create_lazy_string_object (CORE_ADDR address, long length, + const char *encoding, struct type *type) +{ + lazy_string_object *str_obj = NULL; + + if (address == 0) + { + PyErr_SetString (PyExc_MemoryError, + "Cannot create a lazy string from a GDB-side string."); + return NULL; + } + + if (!type) + { + PyErr_SetString (PyExc_RuntimeError, + "A lazy string's type cannot be NULL."); + return NULL; + } + + str_obj = PyObject_New (lazy_string_object, &lazy_string_object_type); + if (!str_obj) + return NULL; + + str_obj->address = address; + str_obj->length = length; + if (encoding == NULL || !strcmp (encoding, "")) + str_obj->encoding = NULL; + else + str_obj->encoding = xstrdup (encoding); + str_obj->type = type; + + return (PyObject *) str_obj; +} + +void +gdbpy_initialize_lazy_string (void) +{ + if (PyType_Ready (&lazy_string_object_type) < 0) + return; + + Py_INCREF (&lazy_string_object_type); +} + +/* Determine whether the printer object pointed to by OBJ is a + Python lazy string. */ +int +gdbpy_is_lazy_string (PyObject *result) +{ + return PyObject_TypeCheck (result, &lazy_string_object_type); +} + +/* Extract and return the actual string from the lazy string object + STRING. Addtionally, the string type is written to *STR_TYPE, the + string length is written to *LENGTH, and the string encoding is + written to *ENCODING. On error, NULL is returned. The caller is + responsible for freeing the returned buffer. */ +gdb_byte * +gdbpy_extract_lazy_string (PyObject *string, struct type **str_type, + long *length, char **encoding) +{ + int width; + int bytes_read; + gdb_byte *buffer = NULL; + int errcode = 0; + CORE_ADDR addr; + struct gdbarch *gdbarch; + enum bfd_endian byte_order; + PyObject *py_len = NULL, *py_encoding = NULL; + PyObject *py_addr = NULL, *py_type = NULL; + volatile struct gdb_exception except; + + py_len = PyObject_GetAttrString (string, "length"); + py_encoding = PyObject_GetAttrString (string, "encoding"); + py_addr = PyObject_GetAttrString (string, "address"); + py_type = PyObject_GetAttrString (string, "type"); + + /* A NULL encoding, length, address or type is not ok. */ + if (!py_len || !py_encoding || !py_addr || !py_type) + goto error; + + *length = PyLong_AsLong (py_len); + addr = PyLong_AsLongLong (py_addr); + + /* If the user supplies Py_None an encoding, set encoding to NULL. + This will trigger the resulting LA_PRINT_CALL to automatically + select an encoding. */ + if (py_encoding == Py_None) + *encoding = NULL; + else + *encoding = xstrdup (PyString_AsString (py_encoding)); + + *str_type = type_object_to_type (py_type); + gdbarch = get_type_arch (*str_type); + byte_order = gdbarch_byte_order (gdbarch); + width = TYPE_LENGTH (*str_type); + + TRY_CATCH (except, RETURN_MASK_ALL) + { + errcode = read_string (addr, *length, width, + *length, byte_order, &buffer, + &bytes_read); + } + if (except.reason < 0) + { + PyErr_Format (except.reason == RETURN_QUIT \ + ? PyExc_KeyboardInterrupt : PyExc_RuntimeError, \ + "%s", except.message); \ + goto error; + + } + + if (errcode) + goto error; + + *length = bytes_read / width; + + Py_DECREF (py_encoding); + Py_DECREF (py_len); + Py_DECREF (py_addr); + Py_DECREF (py_type); + return buffer; + + error: + Py_XDECREF (py_encoding); + Py_XDECREF (py_len); + Py_XDECREF (py_addr); + Py_XDECREF (py_type); + xfree (buffer); + *length = 0; + *str_type = NULL; + return NULL; +} + + + +static PyMethodDef lazy_string_object_methods[] = { + { "value", stpy_convert_to_value, METH_NOARGS, + "Create a (lazy) value that contains a pointer to the string." }, + {NULL} /* Sentinel */ +}; + + +static PyGetSetDef lazy_string_object_getset[] = { + { "address", stpy_get_address, NULL, "Address of the string.", NULL }, + { "encoding", stpy_get_encoding, NULL, "Encoding of the string.", NULL }, + { "length", stpy_get_length, NULL, "Length of the string.", NULL }, + { "type", stpy_get_type, NULL, "Type associated with the string.", NULL }, + { NULL } /* Sentinel */ +}; + +static PyTypeObject lazy_string_object_type = { + PyObject_HEAD_INIT (NULL) + 0, /*ob_size*/ + "gdb.LazyString", /*tp_name*/ + sizeof (lazy_string_object), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + stpy_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash */ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT, /*tp_flags*/ + "GDB lazy string object", /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + lazy_string_object_methods, /* tp_methods */ + 0, /* tp_members */ + lazy_string_object_getset /* tp_getset */ +}; diff --git a/gdb/python/py-prettyprint.c b/gdb/python/py-prettyprint.c index 818cde1..193f97c 100644 --- a/gdb/python/py-prettyprint.c +++ b/gdb/python/py-prettyprint.c @@ -121,6 +121,8 @@ find_pretty_printer (PyObject *value) return function; } + + /* Pretty-print a single value, via the printer object PRINTER. If the function returns a string, a PyObject containing the string is returned. Otherwise, if the function returns a value, @@ -138,7 +140,7 @@ pretty_print_one_value (PyObject *printer, struct value **out_value) result = PyObject_CallMethodObjArgs (printer, gdbpy_to_string_cst, NULL); if (result) { - if (! gdbpy_is_string (result)) + if (! gdbpy_is_string (result) && ! gdbpy_is_lazy_string (result)) { *out_value = convert_value_from_python (result); if (PyErr_Occurred ()) @@ -191,21 +193,47 @@ print_string_repr (PyObject *printer, const char *hint, py_str = pretty_print_one_value (printer, &replacement); if (py_str) { - PyObject *string = python_string_to_target_python_string (py_str); - if (string) + gdb_byte *output = NULL; + long length; + struct type *type; + char *encoding = NULL; + PyObject *string = NULL; + int is_lazy; + + is_lazy = gdbpy_is_lazy_string (py_str); + if (is_lazy) + output = gdbpy_extract_lazy_string (py_str, &type, &length, &encoding); + else { - gdb_byte *output = PyString_AsString (string); - int len = PyString_Size (string); + string = python_string_to_target_python_string (py_str); + if (string) + { + output = PyString_AsString (string); + length = PyString_Size (string); + type = builtin_type (gdbarch)->builtin_char; + } + else + gdbpy_print_stack (); - if (hint && !strcmp (hint, "string")) - LA_PRINT_STRING (stream, builtin_type (gdbarch)->builtin_char, - output, len, 0, options); + } + + if (output) + { + if (is_lazy || (hint && !strcmp (hint, "string"))) + LA_PRINT_STRING (stream, type, output, length, encoding, + 0, options); else fputs_filtered (output, stream); - Py_DECREF (string); } else gdbpy_print_stack (); + + if (string) + Py_DECREF (string); + else + xfree (output); + + xfree (encoding); Py_DECREF (py_str); } else if (replacement) @@ -422,15 +450,30 @@ print_children (PyObject *printer, const char *hint, fputs_filtered (" = ", stream); } - if (gdbpy_is_string (py_v)) + if (gdbpy_is_lazy_string (py_v) || gdbpy_is_string (py_v)) { - char *text = python_string_to_host_string (py_v); - if (! text) - gdbpy_print_stack (); + gdb_byte *output = NULL; + + if (gdbpy_is_lazy_string (py_v)) + { + struct type *type; + long length; + char *encoding = NULL; + + output = gdbpy_extract_lazy_string (py_v, &type, + &length, &encoding); + if (!output) + gdbpy_print_stack (); + LA_PRINT_STRING (stream, type, output, length, encoding, + 0, options); + xfree (encoding); + xfree (output); + } else { - fputs_filtered (text, stream); - xfree (text); + output = python_string_to_host_string (py_v); + fputs_filtered (output, stream); + xfree (output); } } else diff --git a/gdb/python/py-value.c b/gdb/python/py-value.c index af649b0..a792819 100644 --- a/gdb/python/py-value.c +++ b/gdb/python/py-value.c @@ -220,6 +220,36 @@ valpy_get_type (PyObject *self, void *closure) return obj->type; } +/* Implementation of gdb.Value.lazy_string ([encoding] [, length]) -> + string. Return a PyObject representing a lazy_string_object type. + A lazy string is a pointer to a string with an optional encoding and + length. If ENCODING is not given, encoding is set to None. If an + ENCODING is provided the encoding parameter is set to ENCODING, but + the string is not encoded. If LENGTH is provided then the length + parameter is set to LENGTH, otherwise length will be set to -1 (first + null of appropriate with). */ +static PyObject * +valpy_lazy_string (PyObject *self, PyObject *args, PyObject *kw) +{ + int length = -1; + struct value *value = ((value_object *) self)->value; + const char *user_encoding = NULL; + static char *keywords[] = { "encoding", "length", NULL }; + PyObject *str_obj; + + if (!PyArg_ParseTupleAndKeywords (args, kw, "|si", keywords, + &user_encoding, &length)) + return NULL; + + if (TYPE_CODE (value_type (value)) == TYPE_CODE_PTR) + value = value_ind (value); + + str_obj = gdbpy_create_lazy_string_object (value_address (value), length, + user_encoding, value_type (value)); + + return (PyObject *) str_obj; +} + /* Implementation of gdb.Value.string ([encoding] [, errors] [, length]) -> string. Return Unicode string with value contents. If ENCODING is not given, the string is assumed to be encoded in @@ -939,6 +969,13 @@ convert_value_from_python (PyObject *obj) } else if (PyObject_TypeCheck (obj, &value_object_type)) value = value_copy (((value_object *) obj)->value); + else if (gdbpy_is_lazy_string (obj)) + { + PyObject *result; + PyObject *function = PyString_FromString ("value"); + result = PyObject_CallMethodObjArgs (obj, function, NULL); + value = value_copy (((value_object *) result)->value); + } else PyErr_Format (PyExc_TypeError, _("Could not convert Python object: %s"), PyString_AsString (PyObject_Str (obj))); @@ -1001,6 +1038,9 @@ static PyGetSetDef value_object_getset[] = { static PyMethodDef value_object_methods[] = { { "cast", valpy_cast, METH_VARARGS, "Cast the value to the supplied type." }, { "dereference", valpy_dereference, METH_NOARGS, "Dereferences the value." }, + { "lazy_string", (PyCFunction) valpy_lazy_string, METH_VARARGS | METH_KEYWORDS, + "lazy_string ([encoding] [, length]) -> lazy_string\n\ +Return a lazy string representation of the value." }, { "string", (PyCFunction) valpy_string, METH_VARARGS | METH_KEYWORDS, "string ([encoding] [, errors] [, length]) -> string\n\ Return Unicode string representation of the value." }, diff --git a/gdb/python/python-internal.h b/gdb/python/python-internal.h index 62ed538..9196f08 100644 --- a/gdb/python/python-internal.h +++ b/gdb/python/python-internal.h @@ -71,6 +71,8 @@ PyObject *gdbpy_history (PyObject *self, PyObject *args); PyObject *gdbpy_frame_stop_reason_string (PyObject *, PyObject *); PyObject *gdbpy_selected_frame (PyObject *self, PyObject *args); PyObject *gdbpy_lookup_type (PyObject *self, PyObject *args, PyObject *kw); +PyObject *gdbpy_create_lazy_string_object (CORE_ADDR address, long length, + const char *encoding, struct type *type); PyObject *value_to_value_object (struct value *v); PyObject *type_to_type_object (struct type *); @@ -88,6 +90,7 @@ void gdbpy_initialize_commands (void); void gdbpy_initialize_types (void); void gdbpy_initialize_functions (void); void gdbpy_initialize_objfile (void); +void gdbpy_initialize_lazy_string (void); struct cleanup *make_cleanup_py_decref (PyObject *py); @@ -117,6 +120,10 @@ PyObject *python_string_to_target_python_string (PyObject *obj); char *python_string_to_host_string (PyObject *obj); PyObject *target_string_to_unicode (const gdb_byte *str, int length); int gdbpy_is_string (PyObject *obj); +int gdbpy_is_lazy_string (PyObject *result); +gdb_byte *gdbpy_extract_lazy_string (PyObject *string, + struct type **str_type, + long *length, char **encoding); /* Note that these are declared here, and not in python.h with the other pretty-printer functions, because they refer to PyObject. */ diff --git a/gdb/python/python.c b/gdb/python/python.c index 2ac9e99..827372c 100644 --- a/gdb/python/python.c +++ b/gdb/python/python.c @@ -623,6 +623,7 @@ Enables or disables auto-loading of Python code when an object is opened."), gdbpy_initialize_functions (); gdbpy_initialize_types (); gdbpy_initialize_objfile (); + gdbpy_initialize_lazy_string (); PyRun_SimpleString ("import gdb"); PyRun_SimpleString ("gdb.pretty_printers = []"); |