Re: [patch][python] Implement Python lazy strings (PR 10705)

Phil Muldoon
2010-01-13T14:49:51Z

On 01/11/2010 09:08 PM, Tom Tromey wrote:
>>>>>> "Phil" == Phil Muldoon <pmuldoon@redhat.com> writes:
>
> Phil> Index: gdb/varobj.c
> [...]

Here is an updated patch. What do you think?

Cheers,

Phil

--

Index: Makefile.in
===================================================================
RCS file: /cvs/src/src/gdb/Makefile.in,v
retrieving revision 1.1108
diff -u -r1.1108 Makefile.in
--- Makefile.in 12 Jan 2010 21:40:23 -0000 1.1108
+++ Makefile.in 13 Jan 2010 14:13:06 -0000
@@ -270,6 +270,7 @@
py-cmd.o \
py-frame.o \
py-function.o \
+ py-lazy-string.o \
py-objfile.o \
py-prettyprint.o \
py-type.o \
@@ -280,6 +281,7 @@
python/py-cmd.c \
python/py-frame.c \
python/py-function.c \
+ python/py-lazy-string.c \
python/py-objfile.c \
python/py-prettyprint.c \
python/py-type.c \
@@ -1980,6 +1982,10 @@
$(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-function.c
$(POSTCOMPILE)

+py-lazy-string.o: $(srcdir)/python/py-lazy-string.c
+ $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-lazy-string.c
+ $(POSTCOMPILE)
+
py-objfile.o: $(srcdir)/python/py-objfile.c
$(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-objfile.c
$(POSTCOMPILE)
Index: ada-lang.h
===================================================================
RCS file: /cvs/src/src/gdb/ada-lang.h,v
retrieving revision 1.50
diff -u -r1.50 ada-lang.h
--- ada-lang.h 8 Jan 2010 11:58:23 -0000 1.50
+++ ada-lang.h 13 Jan 2010 14:13:06 -0000
@@ -174,7 +174,7 @@
extern void ada_printchar (int, struct type *, struct ui_file *);

extern void ada_printstr (struct ui_file *, struct type *, const gdb_byte *,
- unsigned int, int,
+ unsigned int, const char *, int,
const struct value_print_options *);

struct value *ada_convert_actual (struct value *actual,
Index: ada-valprint.c
===================================================================
RCS file: /cvs/src/src/gdb/ada-valprint.c,v
retrieving revision 1.60
diff -u -r1.60 ada-valprint.c
--- ada-valprint.c 12 Jan 2010 07:45:51 -0000 1.60
+++ ada-valprint.c 13 Jan 2010 14:13:07 -0000
@@ -556,7 +556,7 @@

void
ada_printstr (struct ui_file *stream, struct type *type, const gdb_byte *string,
- unsigned int length, int force_ellipses,
+ unsigned int length, const char *encoding, int force_ellipses,
const struct value_print_options *options)
{
printstr (stream, type, string, length, force_ellipses, TYPE_LENGTH (type),
Index: c-lang.c
===================================================================
RCS file: /cvs/src/src/gdb/c-lang.c,v
retrieving revision 1.79
diff -u -r1.79 c-lang.c
--- c-lang.c 1 Jan 2010 07:31:30 -0000 1.79
+++ c-lang.c 13 Jan 2010 14:13:08 -0000
@@ -369,7 +369,7 @@

void
c_printstr (struct ui_file *stream, struct type *type, const gdb_byte *string,
- unsigned int length, int force_ellipses,
+ unsigned int length, const char *user_encoding, int force_ellipses,
const struct value_print_options *options)
{
enum bfd_endian byte_order = gdbarch_byte_order (get_type_arch (type));
@@ -381,6 +381,7 @@
struct obstack wchar_buf, output;
struct cleanup *cleanup;
enum c_string_type str_type;
+ const char *type_encoding;
const char *encoding;
struct wchar_iterator *iter;
int finished = 0;
@@ -395,7 +396,7 @@
width, byte_order) == 0))
length--;

- str_type = classify_type (type, byte_order, &encoding) & ~C_CHAR;
+ str_type = classify_type (type, byte_order, &type_encoding) & ~C_CHAR;
switch (str_type)
{
case C_STRING:
@@ -411,6 +412,8 @@
break;
}

+ encoding = (user_encoding && *user_encoding) ? user_encoding : type_encoding;
+
if (length == 0)
{
fputs_filtered ("\"\"", stream);
Index: c-lang.h
===================================================================
RCS file: /cvs/src/src/gdb/c-lang.h,v
retrieving revision 1.25
diff -u -r1.25 c-lang.h
--- c-lang.h 1 Jan 2010 07:31:30 -0000 1.25
+++ c-lang.h 13 Jan 2010 14:13:08 -0000
@@ -81,7 +81,7 @@

extern void c_printstr (struct ui_file * stream, struct type *elttype,
const gdb_byte *string, unsigned int length,
- int force_ellipses,
+ const char *user_encoding, int force_ellipses,
const struct value_print_options *options);

extern void c_language_arch_info (struct gdbarch *gdbarch,
Index: c-valprint.c
===================================================================
RCS file: /cvs/src/src/gdb/c-valprint.c,v
retrieving revision 1.64
diff -u -r1.64 c-valprint.c
--- c-valprint.c 1 Jan 2010 07:31:30 -0000 1.64
+++ c-valprint.c 13 Jan 2010 14:13:09 -0000
@@ -198,7 +198,8 @@
}

LA_PRINT_STRING (stream, unresolved_elttype,
- valaddr + embedded_offset, len, 0, options);
+ valaddr + embedded_offset, len,
+ NULL, 0, options);
i = len;
}
else
Index: expprint.c
===================================================================
RCS file: /cvs/src/src/gdb/expprint.c,v
retrieving revision 1.40
diff -u -r1.40 expprint.c
--- expprint.c 1 Jan 2010 07:31:31 -0000 1.40
+++ expprint.c 13 Jan 2010 14:13:10 -0000
@@ -188,7 +188,7 @@
additional parameter to LA_PRINT_STRING. -fnf */
get_user_print_options (&opts);
LA_PRINT_STRING (stream, builtin_type (exp->gdbarch)->builtin_char,
- &exp->elts[pc + 2].string, nargs, 0, &opts);
+ &exp->elts[pc + 2].string, nargs, NULL, 0, &opts);
}
return;

@@ -207,7 +207,7 @@
fputs_filtered ("@\"", stream);
get_user_print_options (&opts);
LA_PRINT_STRING (stream, builtin_type (exp->gdbarch)->builtin_char,
- &exp->elts[pc + 2].string, nargs, 0, &opts);
+ &exp->elts[pc + 2].string, nargs, NULL, 0, &opts);
fputs_filtered ("\"", stream);
}
return;
@@ -293,7 +293,7 @@
struct value_print_options opts;
get_user_print_options (&opts);
LA_PRINT_STRING (stream, builtin_type (exp->gdbarch)->builtin_char,
- tempstr, nargs - 1, 0, &opts);
+ tempstr, nargs - 1, NULL, 0, &opts);
(*pos) = pc;
}
else
Index: f-lang.c
===================================================================
RCS file: /cvs/src/src/gdb/f-lang.c,v
retrieving revision 1.58
diff -u -r1.58 f-lang.c
--- f-lang.c 1 Jan 2010 07:31:31 -0000 1.58
+++ f-lang.c 13 Jan 2010 14:13:10 -0000
@@ -143,7 +143,7 @@

static void
f_printstr (struct ui_file *stream, struct type *type, const gdb_byte *string,
- unsigned int length, int force_ellipses,
+ unsigned int length, const char *encoding, int force_ellipses,
const struct value_print_options *options)
{
unsigned int i;
Index: f-valprint.c
===================================================================
RCS file: /cvs/src/src/gdb/f-valprint.c,v
retrieving revision 1.54
diff -u -r1.54 f-valprint.c
--- f-valprint.c 1 Jan 2010 07:31:31 -0000 1.54
+++ f-valprint.c 13 Jan 2010 14:13:11 -0000
@@ -259,7 +259,7 @@
case TYPE_CODE_STRING:
f77_get_dynamic_length_of_aggregate (type);
LA_PRINT_STRING (stream, builtin_type (gdbarch)->builtin_char,
- valaddr, TYPE_LENGTH (type), 0, options);
+ valaddr, TYPE_LENGTH (type), NULL, 0, options);
break;

case TYPE_CODE_ARRAY:
Index: language.c
===================================================================
RCS file: /cvs/src/src/gdb/language.c,v
retrieving revision 1.93
diff -u -r1.93 language.c
--- language.c 1 Jan 2010 07:31:36 -0000 1.93
+++ language.c 13 Jan 2010 14:13:11 -0000
@@ -1083,7 +1083,7 @@
static void
unk_lang_printstr (struct ui_file *stream, struct type *type,
const gdb_byte *string, unsigned int length,
- int force_ellipses,
+ const char *encoding, int force_ellipses,
const struct value_print_options *options)
{
error (_("internal error - unimplemented function unk_lang_printstr called."));
Index: language.h
===================================================================
RCS file: /cvs/src/src/gdb/language.h,v
retrieving revision 1.61
diff -u -r1.61 language.h
--- language.h 1 Jan 2010 07:31:36 -0000 1.61
+++ language.h 13 Jan 2010 14:13:12 -0000
@@ -190,7 +190,7 @@

void (*la_printstr) (struct ui_file * stream, struct type *elttype,
const gdb_byte *string, unsigned int length,
- int force_ellipses,
+ const char *encoding, int force_ellipses,
const struct value_print_options *);

void (*la_emitchar) (int ch, struct type *chtype,
@@ -389,9 +389,9 @@

#define LA_PRINT_CHAR(ch, type, stream) \
(current_language->la_printchar(ch, type, stream))
-#define LA_PRINT_STRING(stream, elttype, string, length, force_ellipses,options) \
+#define LA_PRINT_STRING(stream, elttype, string, length, encoding, force_ellipses,options) \
(current_language->la_printstr(stream, elttype, string, length, \
- force_ellipses,options))
+ encoding, force_ellipses,options))
#define LA_EMIT_CHAR(ch, type, stream, quoter) \
(current_language->la_emitchar(ch, type, stream, quoter))
#define LA_GET_STRING(value, buffer, length, chartype, encoding) \
Index: m2-lang.c
===================================================================
RCS file: /cvs/src/src/gdb/m2-lang.c,v
retrieving revision 1.53
diff -u -r1.53 m2-lang.c
--- m2-lang.c 1 Jan 2010 07:31:37 -0000 1.53
+++ m2-lang.c 13 Jan 2010 14:13:12 -0000
@@ -104,7 +104,7 @@

static void
m2_printstr (struct ui_file *stream, struct type *type, const gdb_byte *string,
- unsigned int length, int force_ellipses,
+ unsigned int length, const char *encoding, int force_ellipses,
const struct value_print_options *options)
{
unsigned int i;
Index: m2-valprint.c
===================================================================
RCS file: /cvs/src/src/gdb/m2-valprint.c,v
retrieving revision 1.25
diff -u -r1.25 m2-valprint.c
--- m2-valprint.c 1 Jan 2010 07:31:37 -0000 1.25
+++ m2-valprint.c 13 Jan 2010 14:13:12 -0000
@@ -360,8 +360,8 @@
}

LA_PRINT_STRING (stream, TYPE_TARGET_TYPE (type),
- valaddr + embedded_offset, len, 0,
- options);
+ valaddr + embedded_offset, len, NULL,
+ 0, options);
i = len;
}
else
Index: objc-lang.c
===================================================================
RCS file: /cvs/src/src/gdb/objc-lang.c,v
retrieving revision 1.85
diff -u -r1.85 objc-lang.c
--- objc-lang.c 1 Jan 2010 07:31:38 -0000 1.85
+++ objc-lang.c 13 Jan 2010 14:13:14 -0000
@@ -343,7 +343,7 @@
static void
objc_printstr (struct ui_file *stream, struct type *type,
const gdb_byte *string, unsigned int length,
- int force_ellipses,
+ const char *encoding, int force_ellipses,
const struct value_print_options *options)
{
unsigned int i;
Index: p-lang.c
===================================================================
RCS file: /cvs/src/src/gdb/p-lang.c,v
retrieving revision 1.49
diff -u -r1.49 p-lang.c
--- p-lang.c 1 Jan 2010 07:31:38 -0000 1.49
+++ p-lang.c 13 Jan 2010 14:13:14 -0000
@@ -214,7 +214,7 @@
void
pascal_printstr (struct ui_file *stream, struct type *type,
const gdb_byte *string, unsigned int length,
- int force_ellipses,
+ const char *encoding, int force_ellipses,
const struct value_print_options *options)
{
enum bfd_endian byte_order = gdbarch_byte_order (get_type_arch (type));
Index: p-lang.h
===================================================================
RCS file: /cvs/src/src/gdb/p-lang.h,v
retrieving revision 1.20
diff -u -r1.20 p-lang.h
--- p-lang.h 1 Jan 2010 07:31:38 -0000 1.20
+++ p-lang.h 13 Jan 2010 14:13:14 -0000
@@ -54,7 +54,7 @@
extern void pascal_printchar (int, struct type *, struct ui_file *);

extern void pascal_printstr (struct ui_file *, struct type *, const gdb_byte *,
- unsigned int, int,
+ unsigned int, const char *, int,
const struct value_print_options *);

extern struct type **const (pascal_builtin_types[]);
Index: p-valprint.c
===================================================================
RCS file: /cvs/src/src/gdb/p-valprint.c,v
retrieving revision 1.66
diff -u -r1.66 p-valprint.c
--- p-valprint.c 1 Jan 2010 07:31:38 -0000 1.66
+++ p-valprint.c 13 Jan 2010 14:13:15 -0000
@@ -104,7 +104,7 @@
}

LA_PRINT_STRING (stream, TYPE_TARGET_TYPE (type),
- valaddr + embedded_offset, len, 0,
+ valaddr + embedded_offset, len, NULL, 0,
options);
i = len;
}
@@ -306,7 +306,9 @@
&string_pos, &char_type, NULL))
{
len = extract_unsigned_integer (valaddr + embedded_offset + length_pos, length_size, byte_order);
- LA_PRINT_STRING (stream, char_type, valaddr + embedded_offset + string_pos, len, 0, options);
+ LA_PRINT_STRING (stream, char_type,
+ valaddr + embedded_offset + string_pos,
+ len, NULL, 0, options);
}
else
pascal_object_print_value_fields (type, valaddr + embedded_offset, address, stream,
Index: scm-lang.c
===================================================================
RCS file: /cvs/src/src/gdb/scm-lang.c,v
retrieving revision 1.58
diff -u -r1.58 scm-lang.c
--- scm-lang.c 1 Jan 2010 07:31:41 -0000 1.58
+++ scm-lang.c 13 Jan 2010 14:13:15 -0000
@@ -48,7 +48,7 @@

static void
scm_printstr (struct ui_file *stream, struct type *type, const gdb_byte *string,
- unsigned int length, int force_ellipses,
+ unsigned int length, const char *encoding, int force_ellipses,
const struct value_print_options *options)
{
fprintf_filtered (stream, "\"%s\"", string);
Index: valprint.c
===================================================================
RCS file: /cvs/src/src/gdb/valprint.c,v
retrieving revision 1.89
diff -u -r1.89 valprint.c
--- valprint.c 9 Jan 2010 11:46:13 -0000 1.89
+++ valprint.c 13 Jan 2010 14:13:16 -0000
@@ -1452,7 +1452,8 @@
{
fputs_filtered (" ", stream);
}
- LA_PRINT_STRING (stream, elttype, buffer, bytes_read / width, force_ellipsis, options);
+ LA_PRINT_STRING (stream, elttype, buffer, bytes_read / width,
+ NULL, force_ellipsis, options);
}

if (errcode != 0)
Index: varobj.c
===================================================================
RCS file: /cvs/src/src/gdb/varobj.c,v
retrieving revision 1.152
diff -u -r1.152 varobj.c
--- varobj.c 1 Jan 2010 07:31:44 -0000 1.152
+++ varobj.c 13 Jan 2010 14:13:18 -0000
@@ -2453,11 +2453,15 @@
struct cleanup *old_chain;
gdb_byte *thevalue = NULL;
struct value_print_options opts;
- int len = 0;
+ struct type *type = NULL;
+ long len = 0;
+ char *encoding = NULL;
+ struct gdbarch *gdbarch = NULL;

if (value == NULL)
return NULL;

+ gdbarch = get_type_arch (value_type (value));
#if HAVE_PYTHON
{
struct cleanup *back_to = varobj_ensure_python_env (var);
@@ -2489,20 +2493,31 @@
&replacement);
if (output)
{
- PyObject *py_str
- = python_string_to_target_python_string (output);
- if (py_str)
+ if (gdbpy_is_lazy_string (output))
+ {
+ thevalue = gdbpy_extract_lazy_string (output, &type,
+ &len, &encoding);
+ string_print = 1;
+ }
+ else
{
- char *s = PyString_AsString (py_str);
- len = PyString_Size (py_str);
- thevalue = xmemdup (s, len + 1, len + 1);
- Py_DECREF (py_str);
+ PyObject *py_str
+ = python_string_to_target_python_string (output);
+ if (py_str)
+ {
+ char *s = PyString_AsString (py_str);
+ len = PyString_Size (py_str);
+ thevalue = xmemdup (s, len + 1, len + 1);
+ type = builtin_type (gdbarch)->builtin_char;
+ Py_DECREF (py_str);
+ }
}
Py_DECREF (output);
}
if (thevalue && !string_print)
{
do_cleanups (back_to);
+ xfree (encoding);
return thevalue;
}
if (replacement)
@@ -2521,10 +2536,9 @@
opts.raw = 1;
if (thevalue)
{
- struct gdbarch *gdbarch = get_type_arch (value_type (value));
make_cleanup (xfree, thevalue);
- LA_PRINT_STRING (stb, builtin_type (gdbarch)->builtin_char,
- thevalue, len, 0, &opts);
+ make_cleanup (xfree, encoding);
+ LA_PRINT_STRING (stb, type, thevalue, len, encoding, 0, &opts);
}
else
common_val_print (value, stb, 0, &opts, current_language);
Index: doc/gdb.texinfo
===================================================================
RCS file: /cvs/src/src/gdb/doc/gdb.texinfo,v
retrieving revision 1.657
diff -u -r1.657 gdb.texinfo
--- doc/gdb.texinfo 12 Jan 2010 21:40:24 -0000 1.657
+++ doc/gdb.texinfo 13 Jan 2010 14:13:46 -0000
@@ -19420,6 +19420,7 @@
* Functions In Python:: Writing new convenience functions.
* Objfiles In Python:: Object files.
* Frames In Python:: Acessing inferior stack frames from Python.
+* Lazy Strings In Python:: Python representation of lazy strings.
@end menu

@node Basic Python
@@ -19694,6 +19695,30 @@
If the optional @var{length} argument is given, the string will be
fetched and converted to the given length.
@end defmethod
+
+@defmethod Value lazy_string @r{[}encoding@r{]} @r{[}length@r{]}
+If this @code{gdb.Value} represents a string, then this method
+converts the contents to a @code{gdb.LazyString} (@pxref{Lazy Strings
+In Python}). Otherwise, this method will throw an exception.
+
+If the optional @var{encoding} argument is given, it must be a string
+naming the encoding of the @code{gdb.LazyString}. Some examples are:
+@samp{ascii}, @samp{iso-8859-6} or @samp{utf-8}. If the
+@var{encoding} argument is an encoding that @value{GDBN} does
+recognize, @value{GDBN} will raise an error.
+
+When a lazy string is printed, the @value{GDBN} encoding machinery is
+used to convert the string during printing. If the optional
+@var{encoding} argument is not provided, or is an empty string,
+@value{GDBN} will automatically select the encoding most suitable for
+the string type. For further information on encoding in @value{GDBN}
+please see @ref{Character Sets}.
+
+If the optional @var{length} argument is given, the string will be
+fetched and encoded to the length of characters specified. If
+the @var{length} argument is not provided, the string will be fetched
+and encoded until a null of appropriate width is found.
+@end defmethod
@end table

@node Types In Python
@@ -20631,6 +20656,61 @@
@end defmethod
@end table

+@node Lazy Strings In Python
+@subsubsection Python representation of lazy strings.
+
+@cindex lazy strings in python
+@tindex gdb.LazyString
+
+A @dfn{lazy string} is a string whose contents is not retrieved or
+encoded until it is needed.
+
+A @code{gdb.LazyString} is represented in @value{GDBN} as an
+@code{address} that points to a region of memory, an @code{encoding}
+that will be used to encode that region of memory, and a @code{length}
+to delimit the region of memory that represents the string. The
+difference between a @code{gdb.LazyString} and a string wrapped within
+a @code{gdb.Value} is that a @code{gdb.LazyString} will be treated
+differently by @value{GDBN} when printing. A @code{gdb.LazyString} is
+retrieved and encoded during printing, while a @code{gdb.Value}
+wrapping a string is immediately retrieved and encoded on creation.
+
+A @code{gdb.LazyString} object has the following functions:
+
+@defmethod LazyString value
+Convert the @code{gdb.LazyString} to a @code{gdb.Value}. This value
+will point to the string in memory, but will lose all the delayed
+retrieval, encoding and handling that @value{GDBN} applies to a
+@code{gdb.LazyString}.
+@end defmethod
+
+@defivar LazyString address
+This attribute holds the address of the string. This attribute is not
+writable.
+@end defivar
+
+@defivar LazyString length
+This attribute 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. This attribute is not writable.
+@end defivar
+
+@defivar LazyString encoding
+This attribute holds the encoding that will be applied to the string
+when the string is printed by @value{GDBN}. If the encoding is not
+set, or contains an empty string, then @value{GDBN} will select the
+most appropriate encoding when the string is printed. This attribute
+is not writable.
+@end defivar
+
+@defivar LazyString type
+This attribute holds the type that is represented by the lazy string's
+type. For a lazy string this will always be a pointer type. To
+resolve this to the lazy string's character type, use the type's
+@code{target} method. @pxref{Types In Python}. This attribute is not
+writable.
+@end defivar
+
@node Interpreters
@chapter Command Interpreters
@cindex command interpreters
Index: python/py-lazy-string.c
===================================================================
RCS file: python/py-lazy-string.c
diff -N python/py-lazy-string.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ python/py-lazy-string.c 13 Jan 2010 14:13:46 -0000
@@ -0,0 +1,287 @@
+/* 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_len);
+ Py_XDECREF (py_encoding);
+
+ return buffer;
+
+ error:
+ Py_XDECREF (py_encoding);
+ Py_XDECREF (py_len);
+ xfree (buffer);
+ *length = 0;
+ *str_type = NULL;
+ return NULL;
+}
+
+\f
+
+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 */
+};
Index: python/py-prettyprint.c
===================================================================
RCS file: /cvs/src/src/gdb/python/py-prettyprint.c,v
retrieving revision 1.3
diff -u -r1.3 py-prettyprint.c
--- python/py-prettyprint.c 1 Jan 2010 07:31:50 -0000 1.3
+++ python/py-prettyprint.c 13 Jan 2010 14:13:47 -0000
@@ -121,6 +121,8 @@

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 @@
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 @@
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 @@
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
Index: python/py-value.c
===================================================================
RCS file: /cvs/src/src/gdb/python/py-value.c,v
retrieving revision 1.6
diff -u -r1.6 py-value.c
--- python/py-value.c 1 Jan 2010 07:31:50 -0000 1.6
+++ python/py-value.c 13 Jan 2010 14:13:47 -0000
@@ -220,6 +220,36 @@
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 @@
}
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 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." },
Index: python/python-internal.h
===================================================================
RCS file: /cvs/src/src/gdb/python/python-internal.h,v
retrieving revision 1.18
diff -u -r1.18 python-internal.h
--- python/python-internal.h 1 Jan 2010 07:31:50 -0000 1.18
+++ python/python-internal.h 13 Jan 2010 14:13:47 -0000
@@ -71,6 +71,8 @@
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_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 @@
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. */
@@ -125,6 +132,7 @@
PyObject *gdbpy_get_varobj_pretty_printer (struct value *value);
char *gdbpy_get_display_hint (PyObject *printer);
PyObject *gdbpy_default_visualizer (PyObject *self, PyObject *args);
+PyObject *execute_pretty_printer (PyObject *printer);

extern PyObject *gdbpy_doc_cst;
extern PyObject *gdbpy_children_cst;
Index: python/python.c
===================================================================
RCS file: /cvs/src/src/gdb/python/python.c,v
retrieving revision 1.22
diff -u -r1.22 python.c
--- python/python.c 1 Jan 2010 07:31:50 -0000 1.22
+++ python/python.c 13 Jan 2010 14:13:48 -0000
@@ -623,6 +623,7 @@
gdbpy_initialize_functions ();
gdbpy_initialize_types ();
gdbpy_initialize_objfile ();
+ gdbpy_initialize_lazy_string ();

PyRun_SimpleString ("import gdb");
PyRun_SimpleString ("gdb.pretty_printers = []");
Index: testsuite/gdb.python/py-mi.exp
===================================================================
RCS file: /cvs/src/src/gdb/testsuite/gdb.python/py-mi.exp,v
retrieving revision 1.4
diff -u -r1.4 py-mi.exp
--- testsuite/gdb.python/py-mi.exp 1 Jan 2010 07:32:05 -0000 1.4
+++ testsuite/gdb.python/py-mi.exp 13 Jan 2010 14:13:49 -0000
@@ -67,6 +67,10 @@
"struct string_repr" \
"create string_1 varobj"

+mi_create_varobj_checked lstring estring \
+ "struct lazystring" \
+ "create estring varobj"
+
mi_gdb_test "-data-evaluate-expression \"string_1 = string_2\"" ".*" \
"assign string_1 from string_2"

Index: testsuite/gdb.python/py-prettyprint.c
===================================================================
RCS file: /cvs/src/src/gdb/testsuite/gdb.python/py-prettyprint.c,v
retrieving revision 1.3
diff -u -r1.3 py-prettyprint.c
--- testsuite/gdb.python/py-prettyprint.c 1 Jan 2010 07:32:05 -0000 1.3
+++ testsuite/gdb.python/py-prettyprint.c 13 Jan 2010 14:13:50 -0000
@@ -34,6 +34,10 @@
int length;
};

+struct lazystring {
+ const char *lazy_str;
+};
+
#ifdef __cplusplus
struct S : public s {
int zs;
@@ -193,6 +197,7 @@
/* Clearing by being `static' could invoke an other GDB C++ bug. */
struct nullstr nullstr;

+
init_ss(&ss, 1, 2);
init_ss(ssa+0, 3, 4);
init_ss(ssa+1, 5, 6);
@@ -202,6 +207,9 @@
ns.null_str = "embedded\0null\0string";
ns.length = 20;

+ struct lazystring estring;
+ estring.lazy_str = "embedded x\201\202\203\204" ;
+
#ifdef __cplusplus
S cps;

Index: testsuite/gdb.python/py-prettyprint.exp
===================================================================
RCS file: /cvs/src/src/gdb/testsuite/gdb.python/py-prettyprint.exp,v
retrieving revision 1.5
diff -u -r1.5 py-prettyprint.exp
--- testsuite/gdb.python/py-prettyprint.exp 1 Jan 2010 07:32:05 -0000 1.5
+++ testsuite/gdb.python/py-prettyprint.exp 13 Jan 2010 14:13:50 -0000
@@ -102,6 +102,7 @@
gdb_test "print x" " = \"this is x\""
gdb_test "print cstring" " = \"const string\""

+ gdb_test "print estring" "\"embedded x\\\\201\\\\202\\\\203\\\\204\""
gdb_test "print c" " = container \"container\" with 2 elements = {$nl *.0. = 23,$nl *.1. = 72$nl}"

gdb_test "continue" "Program exited normally\."
Index: testsuite/gdb.python/py-prettyprint.py
===================================================================
RCS file: /cvs/src/src/gdb/testsuite/gdb.python/py-prettyprint.py,v
retrieving revision 1.3
diff -u -r1.3 py-prettyprint.py
--- testsuite/gdb.python/py-prettyprint.py 1 Jan 2010 07:32:05 -0000 1.3
+++ testsuite/gdb.python/py-prettyprint.py 13 Jan 2010 14:13:50 -0000
@@ -112,6 +112,18 @@
def display_hint (self):
return 'string'

+class pp_ls:
+ "Print a std::basic_string of some kind"
+
+ def __init__(self, val):
+ self.val = val
+
+ def to_string(self):
+ return self.val['lazy_str'].lazy_string()
+
+ def display_hint (self):
+ return 'string'
+
class pp_outer:
"Print struct outer"

@@ -184,6 +196,9 @@
pretty_printers_dict[re.compile ('^struct ns$')] = pp_ns
pretty_printers_dict[re.compile ('^ns$')] = pp_ns

+ pretty_printers_dict[re.compile ('^struct lazystring$')] = pp_ls
+ pretty_printers_dict[re.compile ('^lazystring$')] = pp_ls
+
pretty_printers_dict[re.compile ('^struct outerstruct$')] = pp_outer
pretty_printers_dict[re.compile ('^outerstruct$')] = pp_outer

Index: testsuite/gdb.python/py-value.c
===================================================================
RCS file: /cvs/src/src/gdb/testsuite/gdb.python/py-value.c,v
retrieving revision 1.3
diff -u -r1.3 py-value.c
--- testsuite/gdb.python/py-value.c 1 Jan 2010 07:32:06 -0000 1.3
+++ testsuite/gdb.python/py-value.c 13 Jan 2010 14:13:50 -0000
@@ -53,6 +53,8 @@
PTR x = &s;
char st[17] = "divide et impera";
char nullst[17] = "divide\0et\0impera";
+ const char *sptr = "pointer";
+ const char *embed = "embedded x\201\202\203\204";
int a[3] = {1,2,3};
int *p = a;
int i = 2;
Index: testsuite/gdb.python/py-value.exp
===================================================================
RCS file: /cvs/src/src/gdb/testsuite/gdb.python/py-value.exp,v
retrieving revision 1.4
diff -u -r1.4 py-value.exp
--- testsuite/gdb.python/py-value.exp 1 Jan 2010 07:32:06 -0000 1.4
+++ testsuite/gdb.python/py-value.exp 13 Jan 2010 14:13:50 -0000
@@ -255,6 +255,19 @@
gdb_test "python print repr(nullst)" "u'divide\\\\x00et'"
}

+proc test_lazy_strings {} {
+
+ global hex
+
+ gdb_test "print sptr" "\"pointer\""
+ gdb_py_test_silent_cmd "python sptr = gdb.history (0)" "Get value from history" 1
+
+ gdb_py_test_silent_cmd "python lstr = sptr.lazy_string()" "Aquire lazy string" 1
+ gdb_test "python print lstr.type" "const char \*." "Test type name equality"
+ gdb_test "python print sptr.type" "const char \*." "Test type name equality"
+}
+
+
# A few objfile tests.
proc test_objfiles {} {
gdb_test "python\nok=False\nfor file in gdb.objfiles():\n if 'py-value' in file.filename:\n ok=True\nprint ok\nend" "True"
@@ -402,6 +415,7 @@
}

test_value_in_inferior
+test_lazy_strings
test_value_after_death

# The following test recompiles the binary to test either C or C++