From: Phil Muldoon <pmuldoon@redhat.com>
To: Tom Tromey <tromey@redhat.com>
Cc: Thiago Jung Bauermann <bauerman@br.ibm.com>,
Project Archer <archer@sourceware.org>
Subject: Re: [python][patch] Preserve string length, and embedded-nulls in pretty-print string emission.
Date: Thu, 18 Jun 2009 12:20:00 -0000 [thread overview]
Message-ID: <4A3A30EB.1080509@redhat.com> (raw)
In-Reply-To: <m38wjs2gu2.fsf@fleche.redhat.com>
[-- Attachment #1: Type: text/plain, Size: 1690 bytes --]
On 06/16/2009 07:07 PM, Tom Tromey wrote:
> Phil> I decided to take a crack at the mechanics of this change this
> Phil> morning. This produces the following hunks (in rough). I can see how
> Phil> just borrowing the underlying data from the PyObject avoids an
> Phil> allocation (the results of PyString_AsString must not be deallocated,
> Phil> etc). Is this what you had in mind?
>
This patch scraps the first value-only approach and as discussed
completely implements the string in PyObject approach. Now strings are
kept in a PyObject (along with their associated length data) until they
are printed, or used in some other way.
What do you think?
Regards
Phil
2009-06-18 Phil Muldoon <pmuldoon@redhat.com>
* python/lib/gdb/libstdcxx/v6/printers.py
(StdStringPrinter.to_string): Extract length from header. Use in
string extraction.
* python/python-internal.h (apply_varobj_pretty_printer): Update
definition.
(python_string_to_target_python_string): Add definition.
* python/python-utils.c (unicode_to_encoded_python_string)
(unicode_to_target_python_string)
(python_string_to_target_python_string): New Functions.
* python/python.c : (print_string_repr): Refactor to logic to account for
PyObject returned strings.
(pretty_print_one_value): Likewise
(apply_varobj_pretty_printer): Likewise.
* varobj.c (value_get_print_value): Refactor logic to account for
PyObject returned strings.
Testsuite ChangeLog:
2009-06-18 Phil Muldoon <pmuldoon@redhat.com>
* gdb.python/python-prettyprint.c: Add counted null string
structure.
* gdb.python/python-prettyprint.exp: Print null string. Test for
embedded nulls.
* gdb.python/python-prettyprint.py (pp_ns): New
Function.
[-- Attachment #2: strings_as_pyobjects.patch --]
[-- Type: text/plain, Size: 14181 bytes --]
diff --git a/gdb/python/lib/gdb/libstdcxx/v6/printers.py b/gdb/python/lib/gdb/libstdcxx/v6/printers.py
index 2bd2593..6bf4f3b 100644
--- a/gdb/python/lib/gdb/libstdcxx/v6/printers.py
+++ b/gdb/python/lib/gdb/libstdcxx/v6/printers.py
@@ -468,7 +468,17 @@ class StdStringPrinter:
encoding = gdb.parameter('target-charset')
elif isinstance(encoding, WideEncoding):
encoding = encoding.value
- return self.val['_M_dataplus']['_M_p'].string(encoding)
+ type = self.val.type
+ if type.code == gdb.TYPE_CODE_REF:
+ type = type.target ()
+
+ ptr = self.val ['_M_dataplus']['_M_p']
+ realtype = type.unqualified ().strip_typedefs ()
+ reptype = gdb.lookup_type (str (realtype) + '::_Rep').pointer ()
+ header = ptr.cast(reptype) - 1
+ len = header.dereference ()['_M_length']
+
+ return self.val['_M_dataplus']['_M_p'].string (encoding, length = len)
def display_hint (self):
return 'string'
diff --git a/gdb/python/python-internal.h b/gdb/python/python-internal.h
index 29e55dd..1d90722 100644
--- a/gdb/python/python-internal.h
+++ b/gdb/python/python-internal.h
@@ -169,6 +169,7 @@ void gdbpy_print_stack (void);
PyObject *python_string_to_unicode (PyObject *obj);
char *unicode_to_target_string (PyObject *unicode_str);
char *python_string_to_target_string (PyObject *obj);
+PyObject *python_string_to_target_python_string (PyObject *obj);
char *python_string_to_host_string (PyObject *obj);
PyObject *target_string_to_unicode (const gdb_byte *str, int length);
int gdbpy_is_string (PyObject *obj);
@@ -177,8 +178,8 @@ int gdbpy_is_value_object (PyObject *obj);
/* Note that these are declared here, and not in python.h with the
other pretty-printer functions, because they refer to PyObject. */
-char *apply_varobj_pretty_printer (PyObject *print_obj,
- struct value **replacement);
+PyObject *apply_varobj_pretty_printer (PyObject *print_obj,
+ struct value **replacement);
PyObject *gdbpy_get_varobj_pretty_printer (struct value *value);
PyObject *gdbpy_instantiate_printer (PyObject *cons, PyObject *value);
char *gdbpy_get_display_hint (PyObject *printer);
diff --git a/gdb/python/python-utils.c b/gdb/python/python-utils.c
index f9c9486..45c74a5 100644
--- a/gdb/python/python-utils.c
+++ b/gdb/python/python-utils.c
@@ -122,6 +122,23 @@ unicode_to_encoded_string (PyObject *unicode_str, const char *charset)
return result;
}
+/* Returns a PyObject with the contents of the given unicode string
+ object converted to a named charset. If an error occurs during
+ the conversion, NULL will be returned and a python exception will
+ be set. */
+static PyObject *
+unicode_to_encoded_python_string (PyObject *unicode_str, const char *charset)
+{
+ PyObject *string;
+
+ /* Translate string to named charset. */
+ string = PyUnicode_AsEncodedString (unicode_str, charset, NULL);
+ if (string == NULL)
+ return NULL;
+
+ return string;
+}
+
/* Returns a newly allocated string with the contents of the given unicode
string object converted to the target's charset. If an error occurs during
the conversion, NULL will be returned and a python exception will be set.
@@ -133,6 +150,16 @@ unicode_to_target_string (PyObject *unicode_str)
return unicode_to_encoded_string (unicode_str, target_charset ());
}
+/* Returns a PyObject with the contents of the given unicode string
+ object converted to the target's charset. If an error occurs
+ during the conversion, NULL will be returned and a python exception
+ will be set. */
+PyObject *
+unicode_to_target_python_string (PyObject *unicode_str)
+{
+ return unicode_to_encoded_python_string (unicode_str, target_charset ());
+}
+
/* Converts a python string (8-bit or unicode) to a target string in
the target's charset. Returns NULL on error, with a python exception set.
@@ -152,6 +179,24 @@ python_string_to_target_string (PyObject *obj)
return result;
}
+/* Converts a python string (8-bit or unicode) to a target string in the
+ target's charset. Returns NULL on error, with a python exception
+ set. */
+PyObject *
+python_string_to_target_python_string (PyObject *obj)
+{
+ PyObject *str;
+ PyObject *result;
+
+ str = python_string_to_unicode (obj);
+ if (str == NULL)
+ return NULL;
+
+ result = unicode_to_target_python_string (str);
+ Py_DECREF (str);
+ return result;
+}
+
/* Converts a python string (8-bit or unicode) to a target string in
the host's charset. Returns NULL on error, with a python exception set.
diff --git a/gdb/python/python.c b/gdb/python/python.c
index e97bef8..d13952f 100644
--- a/gdb/python/python.c
+++ b/gdb/python/python.c
@@ -826,41 +826,36 @@ find_pretty_printer (PyObject *value)
return function;
}
-/* Pretty-print a single value, via the printer object PRINTER. If
- the function returns a string, an xmalloc()d copy is returned.
- Otherwise, if the function returns a value, a *OUT_VALUE is set to
- the value, and NULL is returned. On error, *OUT_VALUE is set to
- NULL and NULL is returned. */
-static char *
+/* 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,
+ *OUT_VALUE is set to the value, and NULL is returned. On error,
+ *OUT_VALUE is set to NULL, and NULL is returned. */
+static PyObject *
pretty_print_one_value (PyObject *printer, struct value **out_value)
{
- char *output = NULL;
volatile struct gdb_exception except;
+ PyObject *result = NULL;
TRY_CATCH (except, RETURN_MASK_ALL)
{
- PyObject *result;
-
result = PyObject_CallMethodObjArgs (printer, gdbpy_to_string_cst, NULL);
if (result)
{
- if (gdbpy_is_string (result))
- output = python_string_to_host_string (result);
- else if (PyObject_TypeCheck (result, &value_object_type))
+ if (! gdbpy_is_string (result))
{
- /* If we just call convert_value_from_python for this
- type, we won't know who owns the result. For this
- one case we need to copy the resulting value. */
- struct value *v = value_object_to_value (result);
- *out_value = value_copy (v);
+ *out_value = convert_value_from_python (result);
+ Py_DECREF (result);
+ result = NULL;
+ if (PyErr_Occurred ())
+ *out_value = NULL;
}
- else
- *out_value = convert_value_from_python (result);
- Py_DECREF (result);
}
+ else
+ *out_value = NULL;
}
- return output;
+ return result;
}
/* Instantiate a pretty-printer given a constructor, CONS, and a
@@ -906,18 +901,26 @@ print_string_repr (PyObject *printer, const char *hint,
const struct value_print_options *options,
const struct language_defn *language)
{
- char *output;
struct value *replacement = NULL;
+ PyObject *py_str = NULL;
- output = pretty_print_one_value (printer, &replacement);
- if (output)
+ py_str = pretty_print_one_value (printer, &replacement);
+ if (py_str)
{
- if (hint && !strcmp (hint, "string"))
- LA_PRINT_STRING (stream, (gdb_byte *) output, strlen (output),
- 1, 0, options);
- else
- fputs_filtered (output, stream);
- xfree (output);
+ PyObject *string = python_string_to_target_python_string (py_str);
+ if (string)
+ {
+ gdb_byte *output = PyString_AsString (string);
+ int len = PyString_Size (string) + 1;
+
+ if (hint && !strcmp (hint, "string"))
+ LA_PRINT_STRING (stream, output,
+ len, 1, 0, options);
+ else
+ fputs_filtered (output, stream);
+ Py_DECREF (string);
+ }
+ Py_DECREF (py_str);
}
else if (replacement)
common_val_print (replacement, stream, recurse, options, language);
@@ -1232,28 +1235,31 @@ apply_val_pretty_printer (struct type *type, const gdb_byte *valaddr,
return result;
}
-/* Apply a pretty-printer for the varobj code. PRINTER_OBJ is the
- print object. It must have a 'to_string' method (but this is
- checked by varobj, not here) which takes no arguments and
- returns a string. This function returns an xmalloc()d string if
- the printer returns a string. The printer may return a replacement
- value instead; in this case *REPLACEMENT is set to the replacement
- value, and this function returns NULL. On error, *REPLACEMENT is
- set to NULL and this function also returns NULL. */
-char *
+ /* Apply a pretty-printer for the varobj code. PRINTER_OBJ is the
+ print object. It must have a 'to_string' method (but this is
+ checked by varobj, not here) which takes no arguments and
+ returns a string. The printer will return a value and in the case
+ of a Python string being returned, this function will return a
+ PyObject containing the string. For any other type, *REPLACEMENT is
+ set to the replacement value and this function returns NULL. On
+ error, *REPLACEMENT is set to NULL and this function also returns
+ NULL. */
+PyObject *
apply_varobj_pretty_printer (PyObject *printer_obj,
struct value **replacement)
{
- char *result;
+ int size = 0;
PyGILState_STATE state = PyGILState_Ensure ();
+ PyObject *py_str = NULL;
*replacement = NULL;
- result = pretty_print_one_value (printer_obj, replacement);
- if (result == NULL);
+ py_str = pretty_print_one_value (printer_obj, replacement);
+
+ if (replacement == NULL && py_str == NULL)
gdbpy_print_stack ();
PyGILState_Release (state);
- return result;
+ return py_str;
}
/* Find a pretty-printer object for the varobj module. Returns a new
diff --git a/gdb/testsuite/gdb.python/python-prettyprint.c b/gdb/testsuite/gdb.python/python-prettyprint.c
index 0d9110d..5cc35be 100644
--- a/gdb/testsuite/gdb.python/python-prettyprint.c
+++ b/gdb/testsuite/gdb.python/python-prettyprint.c
@@ -29,6 +29,11 @@ struct ss
struct s b;
};
+struct ns {
+ const char *null_str;
+ int length;
+};
+
#ifdef __cplusplus
struct S : public s {
int zs;
@@ -166,6 +171,10 @@ main ()
init_ss(ssa+1, 5, 6);
memset (&nullstr, 0, sizeof nullstr);
+ struct ns ns;
+ ns.null_str = "embedded\0null\0string";
+ ns.length = 20;
+
#ifdef __cplusplus
S cps;
diff --git a/gdb/testsuite/gdb.python/python-prettyprint.exp b/gdb/testsuite/gdb.python/python-prettyprint.exp
index 47d2fa8..b2dc85d 100644
--- a/gdb/testsuite/gdb.python/python-prettyprint.exp
+++ b/gdb/testsuite/gdb.python/python-prettyprint.exp
@@ -75,6 +75,7 @@ proc run_lang_tests {lang} {
gdb_test "print ref" "= a=<15> b=< a=<8> b=<$hex>>"
gdb_test "print derived" \
" = \{.*<Vbase1> = pp class name: Vbase1.*<Vbase2> = \{.*<VirtualTest> = pp value variable is: 1,.*members of Vbase2:.*_vptr.Vbase2 = $hex.*<Vbase3> = \{.*members of Vbase3.*members of Derived:.*value = 2.*"
+ gdb_test "print ns " "\"embedded\\\\000null\\\\000string\""
}
gdb_test "print x" " = $hex \"this is x\""
diff --git a/gdb/testsuite/gdb.python/python-prettyprint.py b/gdb/testsuite/gdb.python/python-prettyprint.py
index 82e5331..c3e0dc4 100644
--- a/gdb/testsuite/gdb.python/python-prettyprint.py
+++ b/gdb/testsuite/gdb.python/python-prettyprint.py
@@ -99,6 +99,19 @@ class pp_nullstr:
def to_string(self):
return self.val['s'].string(gdb.parameter('target-charset'))
+class pp_ns:
+ "Print a std::basic_string of some kind"
+
+ def __init__(self, val):
+ self.val = val
+
+ def to_string(self):
+ len = self.val['length']
+ return self.val['null_str'].string (gdb.parameter ('target-charset'), length = len)
+
+ def display_hint (self):
+ return 'string'
+
def lookup_function (val):
"Look-up and return a pretty-printer that can print val."
@@ -155,6 +168,8 @@ def register_pretty_printers ():
pretty_printers_dict[re.compile ('^string_repr$')] = string_print
pretty_printers_dict[re.compile ('^container$')] = ContainerPrinter
+ pretty_printers_dict[re.compile ('^struct ns$')] = pp_ns
+ pretty_printers_dict[re.compile ('^ns$')] = pp_ns
pretty_printers_dict = {}
register_pretty_printers ()
diff --git a/gdb/varobj.c b/gdb/varobj.c
index 49b4a43..75f3f17 100644
--- a/gdb/varobj.c
+++ b/gdb/varobj.c
@@ -2250,8 +2250,9 @@ value_get_print_value (struct value *value, enum varobj_display_formats format,
long dummy;
struct ui_file *stb;
struct cleanup *old_chain;
- char *thevalue = NULL;
+ gdb_byte *thevalue = NULL;
struct value_print_options opts;
+ int len = 0;
if (value == NULL)
return NULL;
@@ -2265,6 +2266,7 @@ value_get_print_value (struct value *value, enum varobj_display_formats format,
char *hint;
struct value *replacement;
int string_print = 0;
+ PyObject *output = NULL;
hint = gdbpy_get_display_hint (value_formatter);
if (hint)
@@ -2274,15 +2276,27 @@ value_get_print_value (struct value *value, enum varobj_display_formats format,
xfree (hint);
}
- thevalue = apply_varobj_pretty_printer (value_formatter,
- &replacement);
- if (thevalue && !string_print)
+ output = apply_varobj_pretty_printer (value_formatter, &replacement);
+
+ if (output)
{
- PyGILState_Release (state);
- return thevalue;
+ PyObject *py_str = python_string_to_target_python_string (output);
+ if (py_str)
+ {
+ char *s = PyString_AsString (py_str);
+ len = PyString_Size (py_str) + 1;
+ thevalue = xmemdup (s, len, len);
+ Py_DECREF (py_str);
+ }
+ Py_DECREF (output);
}
if (replacement)
value = replacement;
+ if (thevalue && !string_print)
+ {
+ PyGILState_Release (state);
+ return thevalue;
+ }
}
PyGILState_Release (state);
}
@@ -2297,8 +2311,7 @@ value_get_print_value (struct value *value, enum varobj_display_formats format,
if (thevalue)
{
make_cleanup (xfree, thevalue);
- LA_PRINT_STRING (stb, (gdb_byte *) thevalue, strlen (thevalue),
- 1, 0, &opts);
+ LA_PRINT_STRING (stb, thevalue, len, 1, 0, &opts);
}
else
common_val_print (value, stb, 0, &opts, current_language);
next prev parent reply other threads:[~2009-06-18 12:20 UTC|newest]
Thread overview: 20+ messages / expand[flat|nested] mbox.gz Atom feed top
2009-05-22 20:23 Phil Muldoon
2009-05-27 17:35 ` Tom Tromey
2009-05-27 18:24 ` Phil Muldoon
2009-05-27 20:22 ` Tom Tromey
2009-06-01 16:26 ` Phil Muldoon
2009-06-02 5:11 ` Thiago Jung Bauermann
2009-06-02 23:46 ` Tom Tromey
2009-06-08 10:31 ` Phil Muldoon
2009-06-11 17:12 ` Tom Tromey
2009-06-15 20:50 ` Phil Muldoon
2009-06-16 12:44 ` Phil Muldoon
2009-06-16 18:07 ` Tom Tromey
2009-06-18 12:20 ` Phil Muldoon [this message]
2009-06-18 20:17 ` Tom Tromey
2009-06-18 20:21 ` Tom Tromey
2009-06-23 14:37 ` Phil Muldoon
2009-06-23 16:37 ` Tom Tromey
2009-06-23 16:56 ` Phil Muldoon
2009-06-02 15:38 ` Jonas Maebe
2009-06-02 20:48 ` Phil Muldoon
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=4A3A30EB.1080509@redhat.com \
--to=pmuldoon@redhat.com \
--cc=archer@sourceware.org \
--cc=bauerman@br.ibm.com \
--cc=tromey@redhat.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).