From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 21746 invoked by alias); 13 Jan 2010 14:49:51 -0000 Received: (qmail 21660 invoked by uid 22791); 13 Jan 2010 14:49:43 -0000 X-SWARE-Spam-Status: No, hits=-2.3 required=5.0 tests=AWL,BAYES_00,HK_OBFDOM,SPF_HELO_PASS,SPF_PASS X-Spam-Check-By: sourceware.org Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Wed, 13 Jan 2010 14:49:35 +0000 Received: from int-mx04.intmail.prod.int.phx2.redhat.com (int-mx04.intmail.prod.int.phx2.redhat.com [10.5.11.17]) by mx1.redhat.com (8.13.8/8.13.8) with ESMTP id o0DEnXv0029374 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK) for ; Wed, 13 Jan 2010 09:49:33 -0500 Received: from localhost.localdomain (ovpn01.gateway.prod.ext.phx2.redhat.com [10.5.9.1]) by int-mx04.intmail.prod.int.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id o0DEnVUU009649; Wed, 13 Jan 2010 09:49:32 -0500 Message-ID: <4B4DDD7B.5080204@redhat.com> Date: Wed, 13 Jan 2010 14:49:00 -0000 From: Phil Muldoon User-Agent: Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.1.5) Gecko/20091209 Fedora/3.0-4.fc12 Lightning/1.0pre Thunderbird/3.0 MIME-Version: 1.0 To: tromey@redhat.com CC: gdb-patches ml Subject: Re: [patch][python] Implement Python lazy strings (PR 10705) References: <4B4746A7.90309@redhat.com> In-Reply-To: Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: 7bit X-IsSubscribed: yes Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org X-SW-Source: 2010-01/txt/msg00344.txt.bz2 On 01/11/2010 09:08 PM, Tom Tromey wrote: >>>>>> "Phil" == Phil Muldoon 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 . */ + +#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; +} + + + +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++