* [patch][python] Implement Python lazy strings (PR 10705)
@ 2010-01-08 14:52 Phil Muldoon
2010-01-08 16:25 ` Eli Zaretskii
2010-01-11 21:08 ` Tom Tromey
0 siblings, 2 replies; 14+ messages in thread
From: Phil Muldoon @ 2010-01-08 14:52 UTC (permalink / raw)
To: gdb-patches ml
This patch was originally sent to Project Archer. Previous reference
here:
http://sourceware.org/ml/archer/2009-q4/msg00123.html
The changes asked for there have been implemented into the new
generated patch.
This patch implements Python lazy strings, and also alters the Python
pretty-printing process to handle them accordingly. A Python lazy
string, as implemented here is a pointer, an optional encoding and an
optional length. The contents of the lazy string are not retrieved
until printing, and additionally, they are not encoded with Python's
codec machinery. The are encoded with GDB's encoding machinery at
time of printing. This patch allows Paul's example:
print estring
$1 = "embedded x\201\202\203\204
To be processed correctly through the Python pretty-printing code.
This patch is mainly in response to:
http://sourceware.org/bugzilla/show_bug.cgi?id=10705
Though it will not fix pretty-printers attempting to print
uninitialized data in a backtrace. But it should handle that data as
well as GDB's own printing and encoding mechanisms do now.
There is a small patch required to enable lazy strings with the
libstdc++ printers. I'll submit that when this patch is accepted
upstream. But if you want to try them now, you have to remove the
encoding logic in the std::string printer (we let GDB decide the
encoding, it is more accurate). And also return a lazy_string(length
= len) from the printer over a string().
Tested on X86_64 on archer-tromey-python branch with no regressions.
Cheers,
Phil
--
ChangeLog:
2010-01-08 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)
(is_lazystring, 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 (is_lazy_string): New function.
(extract_lazy_string): Likewise.
(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.
gdb/testsuite ChangeLog:
2010-01-08 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.
gdb/doc ChangeLog:
2010-01-08 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.
--
Index: gdb/Makefile.in
===================================================================
RCS file: /cvs/src/src/gdb/Makefile.in,v
retrieving revision 1.1107
diff -u -r1.1107 Makefile.in
--- gdb/Makefile.in 1 Jan 2010 07:31:28 -0000 1.1107
+++ gdb/Makefile.in 8 Jan 2010 14:22:11 -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 \
@@ -1979,6 +1981,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: gdb/ada-lang.h
===================================================================
RCS file: /cvs/src/src/gdb/ada-lang.h,v
retrieving revision 1.49
diff -u -r1.49 ada-lang.h
--- gdb/ada-lang.h 1 Jan 2010 07:31:29 -0000 1.49
+++ gdb/ada-lang.h 8 Jan 2010 14:22:11 -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: gdb/ada-valprint.c
===================================================================
RCS file: /cvs/src/src/gdb/ada-valprint.c,v
retrieving revision 1.56
diff -u -r1.56 ada-valprint.c
--- gdb/ada-valprint.c 1 Jan 2010 07:31:29 -0000 1.56
+++ gdb/ada-valprint.c 8 Jan 2010 14:22:12 -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: gdb/c-lang.c
===================================================================
RCS file: /cvs/src/src/gdb/c-lang.c,v
retrieving revision 1.79
diff -u -r1.79 c-lang.c
--- gdb/c-lang.c 1 Jan 2010 07:31:30 -0000 1.79
+++ gdb/c-lang.c 8 Jan 2010 14:22:13 -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: gdb/c-lang.h
===================================================================
RCS file: /cvs/src/src/gdb/c-lang.h,v
retrieving revision 1.25
diff -u -r1.25 c-lang.h
--- gdb/c-lang.h 1 Jan 2010 07:31:30 -0000 1.25
+++ gdb/c-lang.h 8 Jan 2010 14:22:13 -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: gdb/c-valprint.c
===================================================================
RCS file: /cvs/src/src/gdb/c-valprint.c,v
retrieving revision 1.64
diff -u -r1.64 c-valprint.c
--- gdb/c-valprint.c 1 Jan 2010 07:31:30 -0000 1.64
+++ gdb/c-valprint.c 8 Jan 2010 14:22:14 -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: gdb/expprint.c
===================================================================
RCS file: /cvs/src/src/gdb/expprint.c,v
retrieving revision 1.40
diff -u -r1.40 expprint.c
--- gdb/expprint.c 1 Jan 2010 07:31:31 -0000 1.40
+++ gdb/expprint.c 8 Jan 2010 14:22:14 -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: gdb/f-lang.c
===================================================================
RCS file: /cvs/src/src/gdb/f-lang.c,v
retrieving revision 1.58
diff -u -r1.58 f-lang.c
--- gdb/f-lang.c 1 Jan 2010 07:31:31 -0000 1.58
+++ gdb/f-lang.c 8 Jan 2010 14:22:14 -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: gdb/f-valprint.c
===================================================================
RCS file: /cvs/src/src/gdb/f-valprint.c,v
retrieving revision 1.54
diff -u -r1.54 f-valprint.c
--- gdb/f-valprint.c 1 Jan 2010 07:31:31 -0000 1.54
+++ gdb/f-valprint.c 8 Jan 2010 14:22:15 -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: gdb/language.c
===================================================================
RCS file: /cvs/src/src/gdb/language.c,v
retrieving revision 1.93
diff -u -r1.93 language.c
--- gdb/language.c 1 Jan 2010 07:31:36 -0000 1.93
+++ gdb/language.c 8 Jan 2010 14:22:16 -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: gdb/language.h
===================================================================
RCS file: /cvs/src/src/gdb/language.h,v
retrieving revision 1.61
diff -u -r1.61 language.h
--- gdb/language.h 1 Jan 2010 07:31:36 -0000 1.61
+++ gdb/language.h 8 Jan 2010 14:22:16 -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: gdb/m2-lang.c
===================================================================
RCS file: /cvs/src/src/gdb/m2-lang.c,v
retrieving revision 1.53
diff -u -r1.53 m2-lang.c
--- gdb/m2-lang.c 1 Jan 2010 07:31:37 -0000 1.53
+++ gdb/m2-lang.c 8 Jan 2010 14:22:17 -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: gdb/m2-valprint.c
===================================================================
RCS file: /cvs/src/src/gdb/m2-valprint.c,v
retrieving revision 1.25
diff -u -r1.25 m2-valprint.c
--- gdb/m2-valprint.c 1 Jan 2010 07:31:37 -0000 1.25
+++ gdb/m2-valprint.c 8 Jan 2010 14:22:17 -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: gdb/objc-lang.c
===================================================================
RCS file: /cvs/src/src/gdb/objc-lang.c,v
retrieving revision 1.85
diff -u -r1.85 objc-lang.c
--- gdb/objc-lang.c 1 Jan 2010 07:31:38 -0000 1.85
+++ gdb/objc-lang.c 8 Jan 2010 14:22:18 -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: gdb/p-lang.c
===================================================================
RCS file: /cvs/src/src/gdb/p-lang.c,v
retrieving revision 1.49
diff -u -r1.49 p-lang.c
--- gdb/p-lang.c 1 Jan 2010 07:31:38 -0000 1.49
+++ gdb/p-lang.c 8 Jan 2010 14:22:18 -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: gdb/p-lang.h
===================================================================
RCS file: /cvs/src/src/gdb/p-lang.h,v
retrieving revision 1.20
diff -u -r1.20 p-lang.h
--- gdb/p-lang.h 1 Jan 2010 07:31:38 -0000 1.20
+++ gdb/p-lang.h 8 Jan 2010 14:22:19 -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: gdb/p-valprint.c
===================================================================
RCS file: /cvs/src/src/gdb/p-valprint.c,v
retrieving revision 1.66
diff -u -r1.66 p-valprint.c
--- gdb/p-valprint.c 1 Jan 2010 07:31:38 -0000 1.66
+++ gdb/p-valprint.c 8 Jan 2010 14:22:20 -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: gdb/scm-lang.c
===================================================================
RCS file: /cvs/src/src/gdb/scm-lang.c,v
retrieving revision 1.58
diff -u -r1.58 scm-lang.c
--- gdb/scm-lang.c 1 Jan 2010 07:31:41 -0000 1.58
+++ gdb/scm-lang.c 8 Jan 2010 14:22:20 -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: gdb/valprint.c
===================================================================
RCS file: /cvs/src/src/gdb/valprint.c,v
retrieving revision 1.88
diff -u -r1.88 valprint.c
--- gdb/valprint.c 1 Jan 2010 07:31:43 -0000 1.88
+++ gdb/valprint.c 8 Jan 2010 14:22:21 -0000
@@ -1451,7 +1451,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: gdb/varobj.c
===================================================================
RCS file: /cvs/src/src/gdb/varobj.c,v
retrieving revision 1.152
diff -u -r1.152 varobj.c
--- gdb/varobj.c 1 Jan 2010 07:31:44 -0000 1.152
+++ gdb/varobj.c 8 Jan 2010 14:22:23 -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,28 @@
&replacement);
if (output)
{
- PyObject *py_str
- = python_string_to_target_python_string (output);
- if (py_str)
+ if (is_lazy_string (output))
+ thevalue = extract_lazy_string (output, &type,
+ &len, &encoding);
+ 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 +2533,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: gdb/doc/gdb.texinfo
===================================================================
RCS file: /cvs/src/src/gdb/doc/gdb.texinfo,v
retrieving revision 1.656
diff -u -r1.656 gdb.texinfo
--- gdb/doc/gdb.texinfo 6 Jan 2010 20:31:28 -0000 1.656
+++ gdb/doc/gdb.texinfo 8 Jan 2010 14:22:47 -0000
@@ -19416,6 +19416,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
@@ -19690,6 +19691,27 @@
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:
+@code{"ascii"}, @code{"iso-8859-6"} or @code{"utf-8"}.
+
+When a lazy string is printed, the @value{GDBN} codec machinery is
+used to convert the string during printing. If @var{encoding} is
+set to @code{None}, or if @var{encoding} is an empty string,
+@value{GDBN} will automatically select the encoding most suitable for
+the string type.
+
+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
@@ -20627,6 +20649,54 @@
@end defmethod
@end table
+@node Lazy Strings In Python
+@subsubsection Python representation of lazy strings.
+
+@cindex lazy strings in python
+@tindex gdb.LazyString
+A @code{gdb.LazyString} can be defined 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 set
+to @code{None} then @value{GDBN} will select the most appropriate
+encoding when the sting 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. This attribute is not writable.
+@end defivar
+
@node Interpreters
@chapter Command Interpreters
@cindex command interpreters
Index: gdb/python/py-lazy-string.c
===================================================================
RCS file: gdb/python/py-lazy-string.c
diff -N gdb/python/py-lazy-string.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ gdb/python/py-lazy-string.c 8 Jan 2010 14:22:48 -0000
@@ -0,0 +1,196 @@
+/* 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"
+
+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 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);
+}
+
+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;
+}
+
+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);
+}
+
+void
+gdbpy_initialize_lazy_string (void)
+{
+ if (PyType_Ready (&lazy_string_object_type) < 0)
+ return;
+
+ Py_INCREF (&lazy_string_object_type);
+}
+
+\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 */
+};
+
+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: gdb/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
--- gdb/python/py-prettyprint.c 1 Jan 2010 07:31:50 -0000 1.3
+++ gdb/python/py-prettyprint.c 8 Jan 2010 14:22:48 -0000
@@ -121,6 +121,100 @@
return function;
}
+
+/* Determine whether the printer object pointed to by OBJ is a
+ Python lazy string. */
+int
+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. Additionally, 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 *
+extract_lazy_string (PyObject *string, struct type **str_type,
+ long *length, char **encoding)
+{
+ struct value *output;
+ int width;
+ int bytes_read;
+ gdb_byte *buffer = NULL;
+ int errcode = 0;
+ struct gdbarch *gdbarch;
+ enum bfd_endian byte_order;
+ PyObject *py_len = NULL, *py_encoding = NULL;
+ volatile struct gdb_exception except;
+
+ output = convert_value_from_python (string);
+
+ /* Lazy strings are pointers, so point to the actual string
+ data. */
+ if (TYPE_CODE (value_type (output)) == TYPE_CODE_PTR)
+ output = value_ind (output);
+
+ py_len = PyObject_GetAttrString (string, "length");
+ py_encoding = PyObject_GetAttrString (string, "encoding");
+
+ /* A NULL encoding or length is not ok. */
+ if (!py_len || !py_encoding)
+ goto error;
+
+ *length = PyLong_AsLong (py_len);
+
+ /* 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 = value_type (output);
+ 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 (value_address (output), *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;
+}
+
+
+
/* 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 +232,7 @@
result = PyObject_CallMethodObjArgs (printer, gdbpy_to_string_cst, NULL);
if (result)
{
- if (! gdbpy_is_string (result))
+ if (! gdbpy_is_string (result) && ! is_lazy_string (result))
{
*out_value = convert_value_from_python (result);
if (PyErr_Occurred ())
@@ -191,21 +285,48 @@
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 = 0;
+
+ is_lazy = is_lazy_string (py_str);
+ if (is_lazy)
+ output = extract_lazy_string (py_str, &type, &length,
+ &encoding);
+ else
+ {
+ 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 (output)
{
- gdb_byte *output = PyString_AsString (string);
- int len = PyString_Size (string);
-
- if (hint && !strcmp (hint, "string"))
- LA_PRINT_STRING (stream, builtin_type (gdbarch)->builtin_char,
- output, len, 0, options);
+ 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 +543,28 @@
fputs_filtered (" = ", stream);
}
- if (gdbpy_is_string (py_v))
+ if (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;
+ struct type *type;
+ long length;
+ char *encoding = NULL;
+
+ if (is_lazy_string (py_v))
+ {
+ output = 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: gdb/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
--- gdb/python/py-value.c 1 Jan 2010 07:31:50 -0000 1.6
+++ gdb/python/py-value.c 8 Jan 2010 14:22:49 -0000
@@ -220,6 +220,33 @@
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;
+
+ 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 +966,13 @@
}
else if (PyObject_TypeCheck (obj, &value_object_type))
value = value_copy (((value_object *) obj)->value);
+ else if (PyObject_TypeCheck (obj, &lazy_string_object_type))
+ {
+ 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 +1035,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: gdb/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
--- gdb/python/python-internal.h 1 Jan 2010 07:31:50 -0000 1.18
+++ gdb/python/python-internal.h 8 Jan 2010 14:22:49 -0000
@@ -66,11 +66,14 @@
extern PyObject *gdb_module;
extern PyTypeObject value_object_type;
+extern PyTypeObject lazy_string_object_type;
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 +91,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 +121,11 @@
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 is_lazy_string (PyObject *result);
+gdb_byte *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 +134,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: gdb/python/python.c
===================================================================
RCS file: /cvs/src/src/gdb/python/python.c,v
retrieving revision 1.22
diff -u -r1.22 python.c
--- gdb/python/python.c 1 Jan 2010 07:31:50 -0000 1.22
+++ gdb/python/python.c 8 Jan 2010 14:22:49 -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: gdb/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
--- gdb/testsuite/gdb.python/py-mi.exp 1 Jan 2010 07:32:05 -0000 1.4
+++ gdb/testsuite/gdb.python/py-mi.exp 8 Jan 2010 14:22:51 -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: gdb/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
--- gdb/testsuite/gdb.python/py-prettyprint.c 1 Jan 2010 07:32:05 -0000 1.3
+++ gdb/testsuite/gdb.python/py-prettyprint.c 8 Jan 2010 14:22:51 -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: gdb/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
--- gdb/testsuite/gdb.python/py-prettyprint.exp 1 Jan 2010 07:32:05 -0000 1.5
+++ gdb/testsuite/gdb.python/py-prettyprint.exp 8 Jan 2010 14:22:51 -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: gdb/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
--- gdb/testsuite/gdb.python/py-prettyprint.py 1 Jan 2010 07:32:05 -0000 1.3
+++ gdb/testsuite/gdb.python/py-prettyprint.py 8 Jan 2010 14:22:51 -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: gdb/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
--- gdb/testsuite/gdb.python/py-value.c 1 Jan 2010 07:32:06 -0000 1.3
+++ gdb/testsuite/gdb.python/py-value.c 8 Jan 2010 14:22:51 -0000
@@ -53,6 +53,8 @@
PTR x = &s;
char st[17] = "divide et impera";
char nullst[17] = "divide\0et\0impera";
+ const char *sptr = "pointer";
+
int a[3] = {1,2,3};
int *p = a;
int i = 2;
Index: gdb/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
--- gdb/testsuite/gdb.python/py-value.exp 1 Jan 2010 07:32:06 -0000 1.4
+++ gdb/testsuite/gdb.python/py-value.exp 8 Jan 2010 14:22:52 -0000
@@ -255,6 +255,22 @@
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 "print /d &sptr" "Get string address" 1
+ gdb_py_test_silent_cmd "python saddr = 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.address == saddr" "True." "Test address equality"
+ gdb_test "python print lstr.type" "const char \*." "Test type name equality"
+ gdb_test "python print sptr.type" "const char \*." "Test type name equality"
+ gdb_test "python print lstr.value()" "\"pointer\"" "Test value fetch"
+}
+
+
# 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 +418,7 @@
}
test_value_in_inferior
+test_lazy_strings
test_value_after_death
# The following test recompiles the binary to test either C or C++
^ permalink raw reply [flat|nested] 14+ messages in thread* Re: [patch][python] Implement Python lazy strings (PR 10705)
2010-01-08 14:52 [patch][python] Implement Python lazy strings (PR 10705) Phil Muldoon
@ 2010-01-08 16:25 ` Eli Zaretskii
2010-01-11 15:40 ` Phil Muldoon
2010-01-11 21:08 ` Tom Tromey
1 sibling, 1 reply; 14+ messages in thread
From: Eli Zaretskii @ 2010-01-08 16:25 UTC (permalink / raw)
To: Phil Muldoon; +Cc: gdb-patches
> Date: Fri, 08 Jan 2010 14:52:23 +0000
> From: Phil Muldoon <pmuldoon@redhat.com>
>
> This patch implements Python lazy strings, and also alters the Python
> pretty-printing process to handle them accordingly.
Thanks.
> Index: gdb/doc/gdb.texinfo
> ===================================================================
> RCS file: /cvs/src/src/gdb/doc/gdb.texinfo,v
> retrieving revision 1.656
> diff -u -r1.656 gdb.texinfo
> --- gdb/doc/gdb.texinfo 6 Jan 2010 20:31:28 -0000 1.656
> +++ gdb/doc/gdb.texinfo 8 Jan 2010 14:22:47 -0000
A few comments about this part.
> +If the optional @var{encoding} argument is given, it must be a string
> +naming the encoding of the @code{gdb.LazyString}. Some examples are:
^^
Two spaces, please.
> +@code{"ascii"}, @code{"iso-8859-6"} or @code{"utf-8"}.
@code{"foo"} looks funny in the Info manual (because @code encloses
its argument in another pair of quotes. I suggest @samp{ascii}
etc. (without quotes) instead. (Yes, I know we use @code{"foo"}
elsewhere in the manual; they need to be fixed as well.)
> +When a lazy string is printed, the @value{GDBN} codec machinery is
> +used to convert the string during printing.
We don't use ``codec'' for GDB encodings. I suggest to use
``encoding'' here, and perhaps also add a @pxref to the section where
that is described.
> If @var{encoding} is set to @code{None}
Is it None or "None" (a string)? If the former, then your original
statement that it should be a string, seems to be inaccurate.
> or if @var{encoding} is an empty string,
> +@value{GDBN} will automatically select the encoding most suitable for
> +the string type.
This leaves me wondering what will happen if I don't specify the
encoding at all, and how is that different from specifying None.
Also, what happens if the encoding is not known or not supported by
GDB?
> +If the optional @var{length} argument is given, the string will be
> +fetched and encoded to the length of characters specified.
^^^^^^^^^^^^^^^^^^^^^^^^^^^
"to the number of characters" is better, I think. By the way, does it
count characters or bytes?
> +@node Lazy Strings In Python
> +@subsubsection Python representation of lazy strings.
> +
> +@cindex lazy strings in python
> +@tindex gdb.LazyString
It would be good to say here what is a lazy string, before you start
using it to explain other matters. Something like
A @dfn{lazy string} is a string whose contents is not produced until
it is needed.
> +A @code{gdb.LazyString} can be defined as an @code{address} that
"can be defined" or "is represented in GDB"? That is, you are
describing the actual implementation, not a possibility, right?
> +@defivar LazyString type
> +This attribute holds the type that is represented by the lazy string's
> +type. This attribute is not writable.
> +@end defivar
What could be a type of a string, except string? I think the possible
types should be stated here.
^ permalink raw reply [flat|nested] 14+ messages in thread* Re: [patch][python] Implement Python lazy strings (PR 10705)
2010-01-08 16:25 ` Eli Zaretskii
@ 2010-01-11 15:40 ` Phil Muldoon
2010-01-11 19:10 ` Eli Zaretskii
0 siblings, 1 reply; 14+ messages in thread
From: Phil Muldoon @ 2010-01-11 15:40 UTC (permalink / raw)
To: Eli Zaretskii; +Cc: gdb-patches
On 01/08/2010 04:25 PM, Eli Zaretskii wrote:
>> Date: Fri, 08 Jan 2010 14:52:23 +0000
>> From: Phil Muldoon <pmuldoon@redhat.com>
>>
>> This patch implements Python lazy strings, and also alters the Python
>> pretty-printing process to handle them accordingly.
>
> Thanks.
Thanks for the review. I've updated the patch in accordance with your
requests. How does this look? For brevity this time I just included
the patch against gdb.texinfo.
Cheers,
Phil
--
Index: doc/gdb.texinfo
===================================================================
RCS file: /cvs/src/src/gdb/doc/gdb.texinfo,v
retrieving revision 1.656
diff -u -r1.656 gdb.texinfo
--- doc/gdb.texinfo 6 Jan 2010 20:31:28 -0000 1.656
+++ doc/gdb.texinfo 11 Jan 2010 15:34:10 -0000
@@ -19416,6 +19416,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
@@ -19690,6 +19691,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: @pxref{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
@@ -20627,6 +20652,60 @@
@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
^ permalink raw reply [flat|nested] 14+ messages in thread* Re: [patch][python] Implement Python lazy strings (PR 10705)
2010-01-11 15:40 ` Phil Muldoon
@ 2010-01-11 19:10 ` Eli Zaretskii
0 siblings, 0 replies; 14+ messages in thread
From: Eli Zaretskii @ 2010-01-11 19:10 UTC (permalink / raw)
To: Phil Muldoon; +Cc: gdb-patches
> Date: Mon, 11 Jan 2010 15:39:59 +0000
> From: Phil Muldoon <pmuldoon@redhat.com>
> CC: gdb-patches@sourceware.org
>
> Thanks for the review. I've updated the patch in accordance with your
> requests. How does this look?
It's good to go, but please fix one small error in usage of Texinfo:
> +the string type. For further information on encoding in @value{GDBN}
> +please see: @pxref{Character Sets}.
^^^^^^^^^^^^^^^^^^^^^^^^^^^
You want "see @ref{Character Sets}." here. @pxref is for
cross-references that you put in parentheses.
> +@pxref{Types In Python}. This attribute is not writable.
Two spaces, please.
Thanks.
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [patch][python] Implement Python lazy strings (PR 10705)
2010-01-08 14:52 [patch][python] Implement Python lazy strings (PR 10705) Phil Muldoon
2010-01-08 16:25 ` Eli Zaretskii
@ 2010-01-11 21:08 ` Tom Tromey
2010-01-11 21:30 ` Phil Muldoon
2010-01-13 14:49 ` Phil Muldoon
1 sibling, 2 replies; 14+ messages in thread
From: Tom Tromey @ 2010-01-11 21:08 UTC (permalink / raw)
To: Phil Muldoon; +Cc: gdb-patches ml
>>>>> "Phil" == Phil Muldoon <pmuldoon@redhat.com> writes:
Phil> Index: gdb/varobj.c
[...]
Phil> + if (is_lazy_string (output))
Phil> + thevalue = extract_lazy_string (output, &type,
Phil> + &len, &encoding);
Phil> + else
Phil> {
Phil> - char *s = PyString_AsString (py_str);
Phil> - len = PyString_Size (py_str);
Phil> - thevalue = xmemdup (s, len + 1, len + 1);
Phil> - Py_DECREF (py_str);
Phil> + PyObject *py_str
Phil> + = python_string_to_target_python_string (output);
Phil> + if (py_str)
Phil> + {
Phil> + char *s = PyString_AsString (py_str);
Phil> + len = PyString_Size (py_str);
Phil> + thevalue = xmemdup (s, len + 1, len + 1);
Phil> + type = builtin_type (gdbarch)->builtin_char;
Phil> + Py_DECREF (py_str);
Phil> + }
Phil> }
Phil> Py_DECREF (output);
Phil> }
Phil> if (thevalue && !string_print)
Phil> {
Phil> do_cleanups (back_to);
Phil> + xfree (encoding);
Phil> return thevalue;
This is wrong in the lazy string case, because you are returning raw
bytes, but the user expects them to be interpreted according to the
encoding.
We discussed this on irc and I thought the result was that we agreed
that in this case we would pretend that a "string" hint was given.
One way to do this would be to set "string_print = 1" in the lazy case.
The documentation for the "string" hint should mention this.
Phil> +PyObject *
Phil> +gdbpy_create_lazy_string_object (CORE_ADDR address, long length,
Phil> + const char *encoding, struct type *type)
Phil> +{
[...]
Phil> + if (!str_obj)
Phil> + return NULL;
Indentation looks wrong on the second line.
Phil> +/* Determine whether the printer object pointed to by OBJ is a
Phil> + Python lazy string. */
Phil> +int
Phil> +is_lazy_string (PyObject *result)
Phil> +{
Phil> + return PyObject_TypeCheck (result, &lazy_string_object_type);
Phil> +}
Why here and not in py-lazy-string.c?
Then lazy_string_object_type could be static.
Phil> +/* Extract and return the actual string from the lazy string object
Phil> + STRING. Additionally, the string type is written to *STR_TYPE, the
Phil> + string length is written to *LENGTH, and the string encoding is
Phil> + written to *ENCODING. On error, NULL is returned. The caller is
Phil> + responsible for freeing the returned buffer. */
Phil> +gdb_byte *
Phil> +extract_lazy_string (PyObject *string, struct type **str_type,
Phil> + long *length, char **encoding)
Likewise.
Phil> + output = convert_value_from_python (string);
Why do we need to do this?
Can't we just get the address directly?
Phil> + TRY_CATCH (except, RETURN_MASK_ALL)
Phil> + {
Phil> +
Extra blank line.
Phil> + if (except.reason < 0)
Phil> + {
Phil> +
Likewise.
Phil> +}
Phil> +
Phil> +
Phil> +
Likewise.
Phil> + int is_lazy = 0;
Phil> +
Phil> + is_lazy = is_lazy_string (py_str);
There's no need to initialize is_lazy to 0 if you then immediately
assign to it.
Phil> + gdb_byte *output = NULL;
Phil> + struct type *type;
Phil> + long length;
Phil> + char *encoding = NULL;
Phil> +
Phil> + if (is_lazy_string (py_v))
Phil> + {
Phil> + output = extract_lazy_string (py_v, &type, &length, &encoding);
Phil> + if (!output)
Phil> + gdbpy_print_stack ();
Phil> + LA_PRINT_STRING (stream, type, output, length, encoding,
Phil> + 0, options);
Phil> + xfree (encoding);
Phil> + xfree (output);
Variables like 'encoding' that are only used in one branch of the if
should just be declared in that branch.
Tom
^ permalink raw reply [flat|nested] 14+ messages in thread* Re: [patch][python] Implement Python lazy strings (PR 10705)
2010-01-11 21:08 ` Tom Tromey
@ 2010-01-11 21:30 ` Phil Muldoon
2010-01-11 21:40 ` Phil Muldoon
2010-01-12 17:02 ` Tom Tromey
2010-01-13 14:49 ` Phil Muldoon
1 sibling, 2 replies; 14+ messages in thread
From: Phil Muldoon @ 2010-01-11 21:30 UTC (permalink / raw)
To: tromey; +Cc: gdb-patches ml
On 01/11/2010 09:08 PM, Tom Tromey wrote:
>>>>>> "Phil" == Phil Muldoon <pmuldoon@redhat.com> writes:
>
> Phil> Index: gdb/varobj.c
> [...]
> Phil> + if (is_lazy_string (output))
> Phil> + thevalue = extract_lazy_string (output, &type,
> Phil> + &len, &encoding);
> Phil> + else
> Phil> {
> Phil> - char *s = PyString_AsString (py_str);
> Phil> - len = PyString_Size (py_str);
> Phil> - thevalue = xmemdup (s, len + 1, len + 1);
> Phil> - Py_DECREF (py_str);
> Phil> + PyObject *py_str
> Phil> + = python_string_to_target_python_string (output);
> Phil> + if (py_str)
> Phil> + {
> Phil> + char *s = PyString_AsString (py_str);
> Phil> + len = PyString_Size (py_str);
> Phil> + thevalue = xmemdup (s, len + 1, len + 1);
> Phil> + type = builtin_type (gdbarch)->builtin_char;
> Phil> + Py_DECREF (py_str);
> Phil> + }
> Phil> }
> Phil> Py_DECREF (output);
> Phil> }
> Phil> if (thevalue && !string_print)
> Phil> {
> Phil> do_cleanups (back_to);
> Phil> + xfree (encoding);
> Phil> return thevalue;
>
> This is wrong in the lazy string case, because you are returning raw
> bytes, but the user expects them to be interpreted according to the
> encoding.
>
> We discussed this on irc and I thought the result was that we agreed
> that in this case we would pretend that a "string" hint was given.
We did. This case is slightly different case from original case we
discussed in irc (the original was in the non-mi case). Anyway, if
thevalue is not NULL (and in these cases it won't) it is printed via
LA_PRINT_STRING (just a few lines further past this patch hunk) and
the encoding happens at that point.
>
> Phil> +PyObject *
> Phil> +gdbpy_create_lazy_string_object (CORE_ADDR address, long length,
> Phil> + const char *encoding, struct type *type)
> Phil> +{
> [...]
> Phil> + if (!str_obj)
> Phil> + return NULL;
>
> Indentation looks wrong on the second line.
Ok.
> Phil> +/* Determine whether the printer object pointed to by OBJ is a
> Phil> + Python lazy string. */
> Phil> +int
> Phil> +is_lazy_string (PyObject *result)
> Phil> +{
> Phil> + return PyObject_TypeCheck (result, &lazy_string_object_type);
> Phil> +}
>
> Why here and not in py-lazy-string.c?
> Then lazy_string_object_type could be static.
Ok.
> Phil> +/* Extract and return the actual string from the lazy string object
> Phil> + STRING. Additionally, the string type is written to *STR_TYPE, the
> Phil> + string length is written to *LENGTH, and the string encoding is
> Phil> + written to *ENCODING. On error, NULL is returned. The caller is
> Phil> + responsible for freeing the returned buffer. */
> Phil> +gdb_byte *
> Phil> +extract_lazy_string (PyObject *string, struct type **str_type,
> Phil> + long *length, char **encoding)
>
> Likewise.
Ok.
> Phil> + output = convert_value_from_python (string);
>
> Why do we need to do this?
> Can't we just get the address directly?
As a lazy string is a pointer, the code needs to actually find the
type associated with the characters in the string. So later in the
code:
if (TYPE_CODE (value_type (output)) == TYPE_CODE_PTR)
output = value_ind (output);
I originally though about doing this in the creation of a lazy
string. But if that value is processed through common_val_print (say
in non a pretty printing case) the output for "foo" would be:
"f"
But if it is left as a pointer type it prints as:
"foo"
I'm not adverse to performing the value_ind action in the creation of the
lazy string. I just thought it would be nice to allow lazy strings to
print by common_val_print as well as our specialized case.
>
> Phil> + TRY_CATCH (except, RETURN_MASK_ALL)
> Phil> + {
> Phil> +
>
> Extra blank line.
>
> Phil> + if (except.reason < 0)
> Phil> + {
> Phil> +
>
> Likewise.
>
> Phil> +}
> Phil> +
> Phil> +
> Phil> +
>
> Likewise.
>
> Phil> + int is_lazy = 0;
> Phil> +
> Phil> + is_lazy = is_lazy_string (py_str);
>
> There's no need to initialize is_lazy to 0 if you then immediately
> assign to it.
Ok.
>
> Variables like 'encoding' that are only used in one branch of the if
> should just be declared in that branch.
Ok. Mea culpa on the obvious mistakes ;)
Cheers
Phil
^ permalink raw reply [flat|nested] 14+ messages in thread* Re: [patch][python] Implement Python lazy strings (PR 10705)
2010-01-11 21:30 ` Phil Muldoon
@ 2010-01-11 21:40 ` Phil Muldoon
2010-01-12 17:02 ` Tom Tromey
1 sibling, 0 replies; 14+ messages in thread
From: Phil Muldoon @ 2010-01-11 21:40 UTC (permalink / raw)
To: tromey; +Cc: gdb-patches ml
On 01/11/2010 09:30 PM, Phil Muldoon wrote:
> On 01/11/2010 09:08 PM, Tom Tromey wrote:
>>>>>>> "Phil" == Phil Muldoon <pmuldoon@redhat.com> writes:
>>
>> Phil> Index: gdb/varobj.c
>> [...]
>> Phil> + if (is_lazy_string (output))
>> Phil> + thevalue = extract_lazy_string (output, &type,
>> Phil> + &len, &encoding);
>> Phil> + else
>> Phil> {
>> Phil> - char *s = PyString_AsString (py_str);
>> Phil> - len = PyString_Size (py_str);
>> Phil> - thevalue = xmemdup (s, len + 1, len + 1);
>> Phil> - Py_DECREF (py_str);
>> Phil> + PyObject *py_str
>> Phil> + = python_string_to_target_python_string (output);
>> Phil> + if (py_str)
>> Phil> + {
>> Phil> + char *s = PyString_AsString (py_str);
>> Phil> + len = PyString_Size (py_str);
>> Phil> + thevalue = xmemdup (s, len + 1, len + 1);
>> Phil> + type = builtin_type (gdbarch)->builtin_char;
>> Phil> + Py_DECREF (py_str);
>> Phil> + }
>> Phil> }
>> Phil> Py_DECREF (output);
>> Phil> }
>> Phil> if (thevalue && !string_print)
>> Phil> {
>> Phil> do_cleanups (back_to);
>> Phil> + xfree (encoding);
>> Phil> return thevalue;
>>
>> This is wrong in the lazy string case, because you are returning raw
>> bytes, but the user expects them to be interpreted according to the
>> encoding.
>>
>> We discussed this on irc and I thought the result was that we agreed
>> that in this case we would pretend that a "string" hint was given.
>
> We did. This case is slightly different case from original case we
> discussed in irc (the original was in the non-mi case). Anyway, if
> thevalue is not NULL (and in these cases it won't) it is printed via
> LA_PRINT_STRING (just a few lines further past this patch hunk) and
> the encoding happens at that point.
Oops I spotted the bug just after I sent this. Everything will work if
only string_print is set properly for lazy strings ;) (which you
mentioned ;). Ok, sorry for the noise, I'll set that hint.
^ permalink raw reply [flat|nested] 14+ messages in thread* Re: [patch][python] Implement Python lazy strings (PR 10705)
2010-01-11 21:30 ` Phil Muldoon
2010-01-11 21:40 ` Phil Muldoon
@ 2010-01-12 17:02 ` Tom Tromey
1 sibling, 0 replies; 14+ messages in thread
From: Tom Tromey @ 2010-01-12 17:02 UTC (permalink / raw)
To: Phil Muldoon; +Cc: gdb-patches ml
>>>>> "Phil" == Phil Muldoon <pmuldoon@redhat.com> writes:
Phil> + output = convert_value_from_python (string);
Tom> Why do we need to do this?
Tom> Can't we just get the address directly?
Phil> As a lazy string is a pointer, the code needs to actually find the
Phil> type associated with the characters in the string. So later in the
Phil> code:
Phil> if (TYPE_CODE (value_type (output)) == TYPE_CODE_PTR)
Phil> output = value_ind (output);
Yes, but calling convert_value_from_python means calling a method on the
Lazy_string object to get a Value, then unpacking that -- but the actual
pointer value is directly available in the object.
Tom
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [patch][python] Implement Python lazy strings (PR 10705)
2010-01-11 21:08 ` Tom Tromey
2010-01-11 21:30 ` Phil Muldoon
@ 2010-01-13 14:49 ` Phil Muldoon
2010-01-13 18:13 ` Tom Tromey
2010-01-13 18:24 ` Eli Zaretskii
1 sibling, 2 replies; 14+ messages in thread
From: Phil Muldoon @ 2010-01-13 14:49 UTC (permalink / raw)
To: tromey; +Cc: gdb-patches ml
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++
^ permalink raw reply [flat|nested] 14+ messages in thread* Re: [patch][python] Implement Python lazy strings (PR 10705)
2010-01-13 14:49 ` Phil Muldoon
@ 2010-01-13 18:13 ` Tom Tromey
2010-01-13 20:23 ` Phil Muldoon
2010-01-13 18:24 ` Eli Zaretskii
1 sibling, 1 reply; 14+ messages in thread
From: Tom Tromey @ 2010-01-13 18:13 UTC (permalink / raw)
To: Phil Muldoon; +Cc: gdb-patches ml
>>>>> "Phil" == Phil Muldoon <pmuldoon@redhat.com> writes:
Phil> Here is an updated patch. What do you think?
A couple more notes.
Phil> +gdbpy_extract_lazy_string (PyObject *string, struct type **str_type,
Phil> + long *length, char **encoding)
Phil> +{
[...]
Phil> + py_len = PyObject_GetAttrString (string, "length");
Phil> + py_encoding = PyObject_GetAttrString (string, "encoding");
Phil> + py_addr = PyObject_GetAttrString (string, "address");
Phil> + py_type = PyObject_GetAttrString (string, "type");
[...]
Phil> + Py_DECREF (py_len);
Phil> + Py_XDECREF (py_encoding);
Nothing ever frees py_addr or py_type.
This is true for the error case as well.
Phil> +PyObject *execute_pretty_printer (PyObject *printer);
This is declared but never defined or used.
Tom
^ permalink raw reply [flat|nested] 14+ messages in thread* Re: [patch][python] Implement Python lazy strings (PR 10705)
2010-01-13 18:13 ` Tom Tromey
@ 2010-01-13 20:23 ` Phil Muldoon
2010-01-13 20:33 ` Tom Tromey
0 siblings, 1 reply; 14+ messages in thread
From: Phil Muldoon @ 2010-01-13 20:23 UTC (permalink / raw)
To: tromey, Eli Zaretskii; +Cc: gdb-patches ml
On 01/13/2010 06:13 PM, Tom Tromey wrote:
> Phil> Here is an updated patch. What do you think?
>
> A couple more notes.
On 01/13/2010 06:24 PM, Eli Zaretskii wrote:
> One comment about the doco part:
.
Oops, those gotchas should be fixed now. Appending patch.
Cheers
Phil
--
Index: gdb/Makefile.in
===================================================================
RCS file: /cvs/src/src/gdb/Makefile.in,v
retrieving revision 1.1108
diff -u -r1.1108 Makefile.in
--- gdb/Makefile.in 12 Jan 2010 21:40:23 -0000 1.1108
+++ gdb/Makefile.in 13 Jan 2010 20:16:30 -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: gdb/ada-lang.h
===================================================================
RCS file: /cvs/src/src/gdb/ada-lang.h,v
retrieving revision 1.50
diff -u -r1.50 ada-lang.h
--- gdb/ada-lang.h 8 Jan 2010 11:58:23 -0000 1.50
+++ gdb/ada-lang.h 13 Jan 2010 20:16:30 -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: gdb/ada-valprint.c
===================================================================
RCS file: /cvs/src/src/gdb/ada-valprint.c,v
retrieving revision 1.60
diff -u -r1.60 ada-valprint.c
--- gdb/ada-valprint.c 12 Jan 2010 07:45:51 -0000 1.60
+++ gdb/ada-valprint.c 13 Jan 2010 20:16:32 -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: gdb/c-lang.c
===================================================================
RCS file: /cvs/src/src/gdb/c-lang.c,v
retrieving revision 1.79
diff -u -r1.79 c-lang.c
--- gdb/c-lang.c 1 Jan 2010 07:31:30 -0000 1.79
+++ gdb/c-lang.c 13 Jan 2010 20:16:33 -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: gdb/c-lang.h
===================================================================
RCS file: /cvs/src/src/gdb/c-lang.h,v
retrieving revision 1.25
diff -u -r1.25 c-lang.h
--- gdb/c-lang.h 1 Jan 2010 07:31:30 -0000 1.25
+++ gdb/c-lang.h 13 Jan 2010 20:16:33 -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: gdb/c-valprint.c
===================================================================
RCS file: /cvs/src/src/gdb/c-valprint.c,v
retrieving revision 1.64
diff -u -r1.64 c-valprint.c
--- gdb/c-valprint.c 1 Jan 2010 07:31:30 -0000 1.64
+++ gdb/c-valprint.c 13 Jan 2010 20:16:33 -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: gdb/expprint.c
===================================================================
RCS file: /cvs/src/src/gdb/expprint.c,v
retrieving revision 1.40
diff -u -r1.40 expprint.c
--- gdb/expprint.c 1 Jan 2010 07:31:31 -0000 1.40
+++ gdb/expprint.c 13 Jan 2010 20:16:34 -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: gdb/f-lang.c
===================================================================
RCS file: /cvs/src/src/gdb/f-lang.c,v
retrieving revision 1.58
diff -u -r1.58 f-lang.c
--- gdb/f-lang.c 1 Jan 2010 07:31:31 -0000 1.58
+++ gdb/f-lang.c 13 Jan 2010 20:16:34 -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: gdb/f-valprint.c
===================================================================
RCS file: /cvs/src/src/gdb/f-valprint.c,v
retrieving revision 1.54
diff -u -r1.54 f-valprint.c
--- gdb/f-valprint.c 1 Jan 2010 07:31:31 -0000 1.54
+++ gdb/f-valprint.c 13 Jan 2010 20:16:35 -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: gdb/language.c
===================================================================
RCS file: /cvs/src/src/gdb/language.c,v
retrieving revision 1.93
diff -u -r1.93 language.c
--- gdb/language.c 1 Jan 2010 07:31:36 -0000 1.93
+++ gdb/language.c 13 Jan 2010 20:16:36 -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: gdb/language.h
===================================================================
RCS file: /cvs/src/src/gdb/language.h,v
retrieving revision 1.61
diff -u -r1.61 language.h
--- gdb/language.h 1 Jan 2010 07:31:36 -0000 1.61
+++ gdb/language.h 13 Jan 2010 20:16:36 -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: gdb/m2-lang.c
===================================================================
RCS file: /cvs/src/src/gdb/m2-lang.c,v
retrieving revision 1.53
diff -u -r1.53 m2-lang.c
--- gdb/m2-lang.c 1 Jan 2010 07:31:37 -0000 1.53
+++ gdb/m2-lang.c 13 Jan 2010 20:16:36 -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: gdb/m2-valprint.c
===================================================================
RCS file: /cvs/src/src/gdb/m2-valprint.c,v
retrieving revision 1.25
diff -u -r1.25 m2-valprint.c
--- gdb/m2-valprint.c 1 Jan 2010 07:31:37 -0000 1.25
+++ gdb/m2-valprint.c 13 Jan 2010 20:16:37 -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: gdb/objc-lang.c
===================================================================
RCS file: /cvs/src/src/gdb/objc-lang.c,v
retrieving revision 1.85
diff -u -r1.85 objc-lang.c
--- gdb/objc-lang.c 1 Jan 2010 07:31:38 -0000 1.85
+++ gdb/objc-lang.c 13 Jan 2010 20:16:38 -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: gdb/p-lang.c
===================================================================
RCS file: /cvs/src/src/gdb/p-lang.c,v
retrieving revision 1.49
diff -u -r1.49 p-lang.c
--- gdb/p-lang.c 1 Jan 2010 07:31:38 -0000 1.49
+++ gdb/p-lang.c 13 Jan 2010 20:16:38 -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: gdb/p-lang.h
===================================================================
RCS file: /cvs/src/src/gdb/p-lang.h,v
retrieving revision 1.20
diff -u -r1.20 p-lang.h
--- gdb/p-lang.h 1 Jan 2010 07:31:38 -0000 1.20
+++ gdb/p-lang.h 13 Jan 2010 20:16:38 -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: gdb/p-valprint.c
===================================================================
RCS file: /cvs/src/src/gdb/p-valprint.c,v
retrieving revision 1.66
diff -u -r1.66 p-valprint.c
--- gdb/p-valprint.c 1 Jan 2010 07:31:38 -0000 1.66
+++ gdb/p-valprint.c 13 Jan 2010 20:16:39 -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: gdb/scm-lang.c
===================================================================
RCS file: /cvs/src/src/gdb/scm-lang.c,v
retrieving revision 1.58
diff -u -r1.58 scm-lang.c
--- gdb/scm-lang.c 1 Jan 2010 07:31:41 -0000 1.58
+++ gdb/scm-lang.c 13 Jan 2010 20:16:40 -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: gdb/valprint.c
===================================================================
RCS file: /cvs/src/src/gdb/valprint.c,v
retrieving revision 1.89
diff -u -r1.89 valprint.c
--- gdb/valprint.c 9 Jan 2010 11:46:13 -0000 1.89
+++ gdb/valprint.c 13 Jan 2010 20:16:40 -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: gdb/varobj.c
===================================================================
RCS file: /cvs/src/src/gdb/varobj.c,v
retrieving revision 1.152
diff -u -r1.152 varobj.c
--- gdb/varobj.c 1 Jan 2010 07:31:44 -0000 1.152
+++ gdb/varobj.c 13 Jan 2010 20:16:43 -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: gdb/doc/gdb.texinfo
===================================================================
RCS file: /cvs/src/src/gdb/doc/gdb.texinfo,v
retrieving revision 1.657
diff -u -r1.657 gdb.texinfo
--- gdb/doc/gdb.texinfo 12 Jan 2010 21:40:24 -0000 1.657
+++ gdb/doc/gdb.texinfo 13 Jan 2010 20:17:07 -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. @xref{Types In Python}. This attribute is not
+writable.
+@end defivar
+
@node Interpreters
@chapter Command Interpreters
@cindex command interpreters
Index: gdb/python/py-lazy-string.c
===================================================================
RCS file: gdb/python/py-lazy-string.c
diff -N gdb/python/py-lazy-string.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ gdb/python/py-lazy-string.c 13 Jan 2010 20:17:08 -0000
@@ -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;
+}
+
+\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: gdb/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
--- gdb/python/py-prettyprint.c 1 Jan 2010 07:31:50 -0000 1.3
+++ gdb/python/py-prettyprint.c 13 Jan 2010 20:17:08 -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: gdb/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
--- gdb/python/py-value.c 1 Jan 2010 07:31:50 -0000 1.6
+++ gdb/python/py-value.c 13 Jan 2010 20:17:09 -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: gdb/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
--- gdb/python/python-internal.h 1 Jan 2010 07:31:50 -0000 1.18
+++ gdb/python/python-internal.h 13 Jan 2010 20:17:09 -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. */
Index: gdb/python/python.c
===================================================================
RCS file: /cvs/src/src/gdb/python/python.c,v
retrieving revision 1.22
diff -u -r1.22 python.c
--- gdb/python/python.c 1 Jan 2010 07:31:50 -0000 1.22
+++ gdb/python/python.c 13 Jan 2010 20:17:09 -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: gdb/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
--- gdb/testsuite/gdb.python/py-mi.exp 1 Jan 2010 07:32:05 -0000 1.4
+++ gdb/testsuite/gdb.python/py-mi.exp 13 Jan 2010 20:17:11 -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: gdb/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
--- gdb/testsuite/gdb.python/py-prettyprint.c 1 Jan 2010 07:32:05 -0000 1.3
+++ gdb/testsuite/gdb.python/py-prettyprint.c 13 Jan 2010 20:17:11 -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: gdb/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
--- gdb/testsuite/gdb.python/py-prettyprint.exp 1 Jan 2010 07:32:05 -0000 1.5
+++ gdb/testsuite/gdb.python/py-prettyprint.exp 13 Jan 2010 20:17:11 -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: gdb/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
--- gdb/testsuite/gdb.python/py-prettyprint.py 1 Jan 2010 07:32:05 -0000 1.3
+++ gdb/testsuite/gdb.python/py-prettyprint.py 13 Jan 2010 20:17:11 -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: gdb/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
--- gdb/testsuite/gdb.python/py-value.c 1 Jan 2010 07:32:06 -0000 1.3
+++ gdb/testsuite/gdb.python/py-value.c 13 Jan 2010 20:17:11 -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: gdb/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
--- gdb/testsuite/gdb.python/py-value.exp 1 Jan 2010 07:32:06 -0000 1.4
+++ gdb/testsuite/gdb.python/py-value.exp 13 Jan 2010 20:17:12 -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++
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [patch][python] Implement Python lazy strings (PR 10705)
2010-01-13 14:49 ` Phil Muldoon
2010-01-13 18:13 ` Tom Tromey
@ 2010-01-13 18:24 ` Eli Zaretskii
1 sibling, 0 replies; 14+ messages in thread
From: Eli Zaretskii @ 2010-01-13 18:24 UTC (permalink / raw)
To: Phil Muldoon; +Cc: tromey, gdb-patches
> Date: Wed, 13 Jan 2010 14:49:31 +0000
> From: Phil Muldoon <pmuldoon@redhat.com>
> CC: gdb-patches ml <gdb-patches@sourceware.org>
>
> Here is an updated patch. What do you think?
One comment about the doco part:
> +@code{target} method. @pxref{Types In Python}. This attribute is not
@xref, please, not @pxref. The latter is for parentheses. Sorry that
I didn't catch this before.
^ permalink raw reply [flat|nested] 14+ messages in thread
end of thread, other threads:[~2010-01-14 21:24 UTC | newest]
Thread overview: 14+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2010-01-08 14:52 [patch][python] Implement Python lazy strings (PR 10705) Phil Muldoon
2010-01-08 16:25 ` Eli Zaretskii
2010-01-11 15:40 ` Phil Muldoon
2010-01-11 19:10 ` Eli Zaretskii
2010-01-11 21:08 ` Tom Tromey
2010-01-11 21:30 ` Phil Muldoon
2010-01-11 21:40 ` Phil Muldoon
2010-01-12 17:02 ` Tom Tromey
2010-01-13 14:49 ` Phil Muldoon
2010-01-13 18:13 ` Tom Tromey
2010-01-13 20:23 ` Phil Muldoon
2010-01-13 20:33 ` Tom Tromey
2010-01-14 21:24 ` Phil Muldoon
2010-01-13 18:24 ` Eli Zaretskii
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox