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" \ " = \{.* = pp class name: Vbase1.* = \{.* = pp value variable is: 1,.*members of Vbase2:.*_vptr.Vbase2 = $hex.* = \{.*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);