This is the mail archive of the archer@sourceware.org mailing list for the Archer project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [python][patch] Preserve string length, and embedded-nulls inpretty-print string emission.


Tom Tromey wrote:
Or are there other ideas out there?

Thiago> Without thinking too much about this (i.e. FWIW): perhaps having a new Thiago> struct language method LA_CAN_PRINT_AS_STRING?

That seems like a lot of work for a case where we know we have a
Python string and we just want to print it using the language's string
printer.

Maybe we should just go back to having a special case in
pretty_print_one_value, but have it return a PyObject in the string
case.

Here is a patch that returns a PyObject in the string case. It also incorporate the changes requested in Tom's review. I've included the python printers.py changes for context, though they will not form part of the patch (later diverted to libstdcxx).


What do you think?

Regards

Phil

ChangeLog

2009-06-08 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-frame.c (frapy_read_var): Update
python_string_to_target_string call.
* python/python-internal.h (unicode_to_target_string,
(python_string_to_target_string):
Update definitions to include a size parameter.
* python/python-utils.c (unicode_to_encoded_string): Add size to
parameter list. Write size when completed.
(unicode_to_target_string): Likewise.
(python_string_to_target_string): Likewise.
(apply_varobj_pretty_printer): Return a PyObject if object is a
string.
* python/python.c (pretty_print_one_value): Likewise.
(print_string_repr): Refactor to logic to account for PyObject
returned strings.
(apply_varobj_pretty_printer): Likewise.
* value.c (value_from_string): New len parameter. Use over
strlen call.
* value.h (value_from_string): Update definition.
* varobj.c (update_dynamic_varobj_children): Update
convert_value_from_python_call.
(value_get_print_value): Refactor logic to account for PyObject
returned strings.

Testsuite ChangeLog:

2009-06-08 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.

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-frame.c b/gdb/python/python-frame.c
index ad03c46..9615166 100644
--- a/gdb/python/python-frame.c
+++ b/gdb/python/python-frame.c
@@ -395,7 +395,7 @@ frapy_read_var (PyObject *self, PyObject *args)
       struct cleanup *cleanup;
       volatile struct gdb_exception except;
 
-      var_name = python_string_to_target_string (sym_obj);
+      var_name = python_string_to_target_string (sym_obj, NULL);
       if (!var_name)
 	return NULL;
       cleanup = make_cleanup (xfree, var_name);
diff --git a/gdb/python/python-internal.h b/gdb/python/python-internal.h
index 29e55dd..8203795 100644
--- a/gdb/python/python-internal.h
+++ b/gdb/python/python-internal.h
@@ -167,8 +167,8 @@ PyObject *gdbpy_parameter_value (enum var_types, void *);
 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);
+char *unicode_to_target_string (PyObject *unicode_str, int *size);
+char *python_string_to_target_string (PyObject *obj, int *size);
 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 +177,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..11a9e54 100644
--- a/gdb/python/python-utils.c
+++ b/gdb/python/python-utils.c
@@ -100,45 +100,57 @@ python_string_to_unicode (PyObject *obj)
 }
 
 /* Returns a newly allocated string 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.
+   string object converted to a named charset.  The parameter *SIZE
+   will be set to the size of the string.  If *SIZE is NULL no size
+   information will be returned.  If an error occurs during the
+   conversion, NULL will be returned and a python exception will be
+   set.
 
    The caller is responsible for xfree'ing the string.  */
 static char *
-unicode_to_encoded_string (PyObject *unicode_str, const char *charset)
+unicode_to_encoded_string (PyObject *unicode_str, const char *charset, int *size)
 {
   char *result;
   PyObject *string;
+  Py_ssize_t str_size;
 
   /* Translate string to named charset.  */
   string = PyUnicode_AsEncodedString (unicode_str, charset, NULL);
   if (string == NULL)
     return NULL;
 
-  result = xstrdup (PyString_AsString (string));
+  str_size = PyString_Size (string) + 1;
+  result = xmemdup (PyString_AsString (string), str_size, str_size);
+  if (size != NULL)
+    *size = str_size;
 
   Py_DECREF (string);
 
   return result;
 }
 
-/* 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.
+/* Returns a newly allocated string with the contents of the given
+   unicode string object converted to the target's charset.  The
+   parameter *SIZE will be set to the size of the string.  If *SIZE is
+   NULL no size information will be returned.  If an error occurs
+   during the conversion, NULL will be returned and a python exception
+   will be set.
 
    The caller is responsible for xfree'ing the string.  */
 char *
-unicode_to_target_string (PyObject *unicode_str)
+unicode_to_target_string (PyObject *unicode_str, int *size)
 {
-  return unicode_to_encoded_string (unicode_str, target_charset ());
+  return unicode_to_encoded_string (unicode_str, target_charset (), size);
 }
 
 /* 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.
+   the target's charset.  The parameter *SIZE will be set to the
+   size of the string.  If *SIZE is NULL no size information will be
+   returned.  Returns NULL on error, with a python exception set.
 
    The caller is responsible for xfree'ing the string.  */
 char *
-python_string_to_target_string (PyObject *obj)
+python_string_to_target_string (PyObject *obj, int *size)
 {
   PyObject *str;
   char *result;
@@ -147,7 +159,7 @@ python_string_to_target_string (PyObject *obj)
   if (str == NULL)
     return NULL;
 
-  result = unicode_to_target_string (str);
+  result = unicode_to_target_string (str, size);
   Py_DECREF (str);
   return result;
 }
@@ -166,7 +178,7 @@ python_string_to_host_string (PyObject *obj)
   if (str == NULL)
     return NULL;
 
-  result = unicode_to_encoded_string (str, host_charset ()); 
+  result = unicode_to_encoded_string (str, host_charset (), NULL);
   Py_DECREF (str);
   return result;
 }
diff --git a/gdb/python/python-value.c b/gdb/python/python-value.c
index 743e6a6..7c107f5 100644
--- a/gdb/python/python-value.c
+++ b/gdb/python/python-value.c
@@ -896,12 +896,13 @@ convert_value_from_python (PyObject *obj)
       else if (gdbpy_is_string (obj))
 	{
 	  char *s;
+	  int str_size = 0;
 
-	  s = python_string_to_target_string (obj);
+	  s = python_string_to_target_string (obj, &str_size);
 	  if (s != NULL)
 	    {
 	      old = make_cleanup (xfree, s);
-	      value = value_from_string (s);
+	      value = value_from_string (s, str_size);
 	      do_cleanups (old);
 	    }
 	}
diff --git a/gdb/python/python.c b/gdb/python/python.c
index e97bef8..24f4351 100644
--- a/gdb/python/python.c
+++ b/gdb/python/python.c
@@ -826,41 +826,40 @@ 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;
+  int is_string = 0;
 
   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))
+	  is_string = gdbpy_is_string (result);
+	  if (! is_string)
 	    {
-	      /* 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);
+	      if (PyErr_Occurred ())
+		*out_value = NULL;
 	    }
-	  else
-	    *out_value = convert_value_from_python (result);
-	  Py_DECREF (result);
 	}
+      else
+	*out_value = NULL;
     }
 
-  return output;
+  if (is_string)
+    return result;
+
+  return NULL;
 }
 
 /* Instantiate a pretty-printer given a constructor, CONS, and a
@@ -906,18 +905,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);
+      int len;
+      gdb_byte *output;
+      output = python_string_to_target_string (py_str, &len);
+      if (output)
+	{
+	  struct cleanup *old = make_cleanup (xfree, output);
+	  if (hint && !strcmp (hint, "string"))
+	    LA_PRINT_STRING (stream, output,
+			     len, 1, 0, options);
+	  else
+	    fputs_filtered (output, stream);
+	  do_cleanups (old);
+	}
+      Py_DECREF (py_str);
     }
   else if (replacement)
     common_val_print (replacement, stream, recurse, options, language);
@@ -1232,28 +1239,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 containg 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/value.c b/gdb/value.c
index fd05f07..5f4731e 100644
--- a/gdb/value.c
+++ b/gdb/value.c
@@ -1849,13 +1849,13 @@ value_from_pointer (struct type *type, CORE_ADDR addr)
 /* Create a value for a string constant to be stored locally
    (not in the inferior's memory space, but in GDB memory).
    This is analogous to value_from_longest, which also does not
-   use inferior memory.  String shall NOT contain embedded nulls.  */
+   use inferior memory.  LEN is the length of the string *PTR
+   from which the value will be created.  */
 
 struct value *
-value_from_string (char *ptr)
+value_from_string (char *ptr, int len)
 {
   struct value *val;
-  int len = strlen (ptr);
   int lowbound = current_language->string_lower_bound;
   struct type *string_char_type;
   struct type *rangetype;
diff --git a/gdb/value.h b/gdb/value.h
index fd0d2c9..38c1289 100644
--- a/gdb/value.h
+++ b/gdb/value.h
@@ -295,7 +295,7 @@ extern struct value *value_from_pointer (struct type *type, CORE_ADDR addr);
 extern struct value *value_from_double (struct type *type, DOUBLEST num);
 extern struct value *value_from_decfloat (struct type *type,
 					  const gdb_byte *decbytes);
-extern struct value *value_from_string (char *string);
+extern struct value *value_from_string (char *string, int len);
 
 extern struct value *value_at (struct type *type, CORE_ADDR addr);
 extern struct value *value_at_lazy (struct type *type, CORE_ADDR addr);
diff --git a/gdb/varobj.c b/gdb/varobj.c
index 49b4a43..e176ecd 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 *py_str = NULL;
 
 	hint = gdbpy_get_display_hint (value_formatter);
 	if (hint)
@@ -2274,15 +2276,22 @@ 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)
+	py_str = apply_varobj_pretty_printer (value_formatter, &replacement);
+
+	if (py_str)
 	  {
-	    PyGILState_Release (state);
-	    return thevalue;
+	    thevalue = python_string_to_target_string (py_str, &len);
+	    Py_DECREF(py_str);
 	  }
+
 	if (replacement)
 	  value = replacement;
+
+	if (thevalue && !string_print)
+         {
+           PyGILState_Release (state);
+           return thevalue;
+         }
       }
     PyGILState_Release (state);
   }
@@ -2294,11 +2303,11 @@ value_get_print_value (struct value *value, enum varobj_display_formats format,
   get_formatted_print_options (&opts, format_code[(int) format]);
   opts.deref_ref = 0;
   opts.raw = 1;
+
   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);

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]