2009-07-10 Phil Muldoon <pmuldoon@redhat.com>

* 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-prettyprint.c (pretty_print_one_value): Likewise.
	(print_string_repr): Refactor to logic to account for PyObject
	returned strings.
	(apply_varobj_pretty_printer): Likewise.
	* python/python-value.c (valpy_string): Parse length keyword. Use
	length keyword in LA_GET_STRING.
	* varobj.c (value_get_print_value): Refactor logic to account for
	PyObject returned strings.
	* c-lang.c (c_get_string): If the length parameter is specified,
	use that. Return value in characters. Update comments.
	* language.h: Update c_get_string prototype comments.

2009-07-10  Phil Muldoon  <pmuldoon@redhat.com>

	* gdb.texinfo (Values From Inferior): Add length parameter
	description.

2009-07-10 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.
	* gdb.python/python-value.exp (test_value_in_inferior): Add
	variable length string fetch tests.
	* gdb.python/python-value.c (main): Add strings for string fetch tests.
This commit is contained in:
Phil Muldoon 2009-07-10 10:35:17 +00:00
parent 041de40dc8
commit fbb8f2990c
16 changed files with 267 additions and 83 deletions

View File

@ -1,3 +1,23 @@
2009-07-10 Phil Muldoon <pmuldoon@redhat.com>
* 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-prettyprint.c (pretty_print_one_value): Likewise.
(print_string_repr): Refactor to logic to account for PyObject
returned strings.
(apply_varobj_pretty_printer): Likewise.
* python/python-value.c (valpy_string): Parse length keyword. Use
length keyword in LA_GET_STRING.
* varobj.c (value_get_print_value): Refactor logic to account for
PyObject returned strings.
* c-lang.c (c_get_string): If the length parameter is specified,
use that. Return value in characters. Update comments.
* language.h: Update c_get_string prototype comments.
2009-07-09 Doug Evans <dje@google.com>
* i386-tdep.c (i386_displaced_step_fixup): Fix order of arguments

View File

@ -604,18 +604,17 @@ c_printstr (struct ui_file *stream, struct type *type, const gdb_byte *string,
}
/* Obtain a C string from the inferior storing it in a newly allocated
buffer in BUFFER, which should be freed by the caller. The string is
read until a null character is found. If VALUE is an array with known
length, the function will not read past the end of the array. LENGTH
will contain the size of the string in bytes (not counting the null
character).
Assumes strings are terminated by a null character. The size of a character
is determined by the length of the target type of the pointer or array.
This means that a null byte present in a multi-byte character will not
terminate the string unless the whole character is null.
CHARSET is always set to the target charset. */
buffer in BUFFER, which should be freed by the caller. If the
in- and out-parameter *LENGTH is specified at -1, the string is read
until a null character of the appropriate width is found, otherwise
the string is read to the length of characters specified.
The size of a character is determined by the length of the target
type of the pointer or array. If VALUE is an array with a known
length, the function will not read past the end of the array.
On completion, *LENGTH will be set to the size of the string read in
characters. (If a length of -1 is specified, the length returned
will not include the null character). CHARSET is always set to the
target charset. */
void
c_get_string (struct value *value, gdb_byte **buffer, int *length,
@ -625,6 +624,7 @@ c_get_string (struct value *value, gdb_byte **buffer, int *length,
unsigned int fetchlimit;
struct type *type = check_typedef (value_type (value));
struct type *element_type = TYPE_TARGET_TYPE (type);
int req_length = *length;
enum bfd_endian byte_order = gdbarch_byte_order (get_type_arch (type));
if (element_type == NULL)
@ -661,7 +661,7 @@ c_get_string (struct value *value, gdb_byte **buffer, int *length,
width = TYPE_LENGTH (element_type);
/* If the string lives in GDB's memory intead of the inferior's, then we
/* If the string lives in GDB's memory instead of the inferior's, then we
just need to copy it to BUFFER. Also, since such strings are arrays
with known size, FETCHLIMIT will hold the size of the array. */
if ((VALUE_LVAL (value) == not_lval
@ -671,13 +671,18 @@ c_get_string (struct value *value, gdb_byte **buffer, int *length,
int i;
const gdb_byte *contents = value_contents (value);
/* Look for a null character. */
for (i = 0; i < fetchlimit; i++)
if (extract_unsigned_integer (contents + i * width, width,
byte_order) == 0)
break;
/* I is now either the number of non-null characters, or FETCHLIMIT. */
/* If a length is specified, use that. */
if (*length >= 0)
i = *length;
else
/* Otherwise, look for a null character. */
for (i = 0; i < fetchlimit; i++)
if (extract_unsigned_integer (contents + i * width, width,
byte_order) == 0)
break;
/* I is now either a user-defined length, the number of non-null
characters, or FETCHLIMIT. */
*length = i * width;
*buffer = xmalloc (*length);
memcpy (*buffer, contents, *length);
@ -685,8 +690,8 @@ c_get_string (struct value *value, gdb_byte **buffer, int *length,
}
else
{
err = read_string (value_as_address (value), -1, width, fetchlimit,
byte_order, buffer, length);
err = read_string (value_as_address (value), *length, width, fetchlimit,
byte_order, buffer, length);
if (err)
{
xfree (*buffer);
@ -695,11 +700,22 @@ c_get_string (struct value *value, gdb_byte **buffer, int *length,
}
}
/* If the last character is null, subtract it from LENGTH. */
if (*length > 0
&& extract_unsigned_integer (*buffer + *length - width, width,
byte_order) == 0)
*length -= width;
/* If the LENGTH is specified at -1, we want to return the string
length up to the terminating null character. If an actual length
was specified, we want to return the length of exactly what was
read. */
if (req_length == -1)
/* If the last character is null, subtract it from LENGTH. */
if (*length > 0
&& extract_unsigned_integer (*buffer + *length - width, width,
byte_order) == 0)
*length -= width;
/* The read_string function will return the number of bytes read.
If length returned from read_string was > 0, return the number of
characters read by dividing the number of bytes by width. */
if (*length != 0)
*length = *length / width;
*charset = target_charset ();

View File

@ -1,3 +1,8 @@
2009-07-10 Phil Muldoon <pmuldoon@redhat.com>
* gdb.texinfo (Values From Inferior): Add length parameter
description.
2009-07-04 Chris Genly <chris@genly.us>
* gdb.texinfo (GDB/MI Variable Objects): Document child definition

View File

@ -18894,7 +18894,7 @@ The result @code{bar} will be a @code{gdb.Value} object holding the
value pointed to by @code{foo}.
@end defmethod
@defmethod Value string @r{[}encoding@r{]} @r{[}errors@r{]}
@defmethod Value string @r{[}encoding@r{]} @r{[}errors@r{]} @r{[}length@r{]}
If this @code{gdb.Value} represents a string, then this method
converts the contents to a Python string. Otherwise, this method will
throw an exception.
@ -18905,7 +18905,9 @@ language.
For C-like languages, a value is a string if it is a pointer to or an
array of characters or ints. The string is assumed to be terminated
by a zero of the appropriate width.
by a zero of the appropriate width. However if the optional length
argument is given, the string will be converted to that given length,
ignoring any embedded zeros that the string may contain.
If the optional @var{encoding} argument is given, it must be a string
naming the encoding of the string in the @code{gdb.Value}, such as
@ -18919,6 +18921,9 @@ will be used, if the current language is able to supply one.
The optional @var{errors} argument is the same as the corresponding
argument to Python's @code{string.decode} method.
If the optional @var{length} argument is given, the string will be
fetched and converted to the given length.
@end defmethod
@end table

View File

@ -284,10 +284,15 @@ struct language_defn
int (*la_pass_by_reference) (struct type *type);
/* Obtain a string from the inferior, storing it in a newly allocated
buffer in BUFFER, which should be freed by the caller. LENGTH will
hold the size in bytes of the string (only actual characters, excluding
an eventual terminating null character). CHARSET will hold the encoding
used in the string. */
buffer in BUFFER, which should be freed by the caller. If the
in- and out-parameter *LENGTH is specified at -1, the string is
read until a null character of the appropriate width is found -
otherwise the string is read to the length of characters specified.
On completion, *LENGTH will hold the size of the string in characters.
If a *LENGTH of -1 was specified it will count only actual
characters, excluding any eventual terminating null character.
Otherwise *LENGTH will include all characters - including any nulls.
CHARSET will hold the encoding used in the string. */
void (*la_get_string) (struct value *value, gdb_byte **buffer, int *length,
const char **charset);

View File

@ -113,14 +113,15 @@ 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);
/* 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);
char *gdbpy_get_display_hint (PyObject *printer);
PyObject *gdbpy_default_visualizer (PyObject *self, PyObject *args);

View File

@ -121,34 +121,35 @@ 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;
*out_value = 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
*out_value = convert_value_from_python (result);
Py_DECREF (result);
if (! gdbpy_is_string (result))
{
*out_value = convert_value_from_python (result);
if (PyErr_Occurred ())
*out_value = NULL;
Py_DECREF (result);
result = NULL;
}
}
}
return output;
return result;
}
/* Return the display hint for the object printer, PRINTER. Return
@ -184,19 +185,28 @@ print_string_repr (PyObject *printer, const char *hint,
const struct language_defn *language,
struct gdbarch *gdbarch)
{
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, builtin_type (gdbarch)->builtin_char,
(gdb_byte *) output, strlen (output),
0, options);
PyObject *string = python_string_to_target_python_string (py_str);
if (string)
{
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);
else
fputs_filtered (output, stream);
Py_DECREF (string);
}
else
fputs_filtered (output, stream);
xfree (output);
gdbpy_print_stack ();
Py_DECREF (py_str);
}
else if (replacement)
common_val_print (replacement, stream, recurse, options, language);
@ -511,26 +521,30 @@ 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 *
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;
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 ();
return result;
return py_str;
}
/* Find a pretty-printer object for the varobj module. Returns a new

View File

@ -104,6 +104,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.
@ -115,6 +132,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.
@ -134,6 +161,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.

View File

@ -189,13 +189,16 @@ valpy_get_type (PyObject *self, void *closure)
return obj->type;
}
/* Implementation of gdb.Value.string ([encoding] [, errors]) -> string
Return Unicode string with value contents. If ENCODING is not given,
the string is assumed to be encoded in the target's charset. */
/* 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
the target's charset. If LENGTH is provided, only fetch string to
the length provided. */
static PyObject *
valpy_string (PyObject *self, PyObject *args, PyObject *kw)
{
int length, ret = 0;
int length = -1, ret = 0;
gdb_byte *buffer;
struct value *value = ((value_object *) self)->value;
volatile struct gdb_exception except;
@ -204,10 +207,10 @@ valpy_string (PyObject *self, PyObject *args, PyObject *kw)
const char *errors = NULL;
const char *user_encoding = NULL;
const char *la_encoding = NULL;
static char *keywords[] = { "encoding", "errors" };
static char *keywords[] = { "encoding", "errors", "length" };
if (!PyArg_ParseTupleAndKeywords (args, kw, "|ss", keywords,
&user_encoding, &errors))
if (!PyArg_ParseTupleAndKeywords (args, kw, "|ssi", keywords,
&user_encoding, &errors, &length))
return NULL;
TRY_CATCH (except, RETURN_MASK_ALL)
@ -937,7 +940,7 @@ 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." },
{ "string", (PyCFunction) valpy_string, METH_VARARGS | METH_KEYWORDS,
"string ([encoding] [, errors]) -> string\n\
"string ([encoding] [, errors] [, length]) -> string\n\
Return Unicode string representation of the value." },
{NULL} /* Sentinel */
};

View File

@ -1,3 +1,14 @@
2009-07-10 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.
* gdb.python/python-value.exp (test_value_in_inferior): Add
variable length string fetch tests.
* gdb.python/python-value.c (main): Add strings for string fetch tests.
2009-07-09 Jan Kratochvil <jan.kratochvil@redhat.com>
* gdb.base/dump.exp (inaccessible memory is reported): New test.

View File

@ -27,6 +27,11 @@ struct ss
struct s b;
};
struct ns {
const char *null_str;
int length;
};
#ifdef __cplusplus
struct S : public s {
int zs;
@ -156,6 +161,10 @@ main ()
init_ss(ssa+0, 3, 4);
init_ss(ssa+1, 5, 6);
struct ns ns;
ns.null_str = "embedded\0null\0string";
ns.length = 20;
#ifdef __cplusplus
S cps;

View File

@ -78,6 +78,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\""

View File

@ -92,6 +92,19 @@ class pp_vbase1:
def to_string (self):
return "pp class name: " + self.val.type.tag
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."
@ -145,6 +158,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 ()

View File

@ -44,6 +44,8 @@ main (int argc, char *argv[])
struct s s;
union u u;
PTR x = &s;
char st[17] = "divide et impera";
char nullst[17] = "divide\0et\0impera";
s.a = 3;
s.b = 5;

View File

@ -234,6 +234,25 @@ proc test_value_in_inferior {} {
# Test address attribute
gdb_test "python print 'result =', arg0.address" "= 0x\[\[:xdigit:\]\]+" "Test address attribute"
# Test string fetches, both partial and whole.
gdb_test "print st" "\"divide et impera\""
gdb_py_test_silent_cmd "python st = gdb.history (0)" "get value from history" 1
gdb_test "python print st.string ()" "divide et impera" "Test string with no length"
gdb_test "python print st.string (length = -1)" "divide et impera" "Test string (length = -1) is all of the string"
gdb_test "python print st.string (length = 6)" "divide"
gdb_test "python print \"---\"+st.string (length = 0)+\"---\"" "------" "Test string (length = 0) is empty"
gdb_test "python print len(st.string (length = 0))" "0" "Test length is 0"
# Fetch a string that has embedded nulls.
gdb_test "print nullst" "\"divide\\\\000et\\\\000impera\".*"
gdb_py_test_silent_cmd "python nullst = gdb.history (0)" "get value from history" 1
gdb_test "python print nullst.string ()" "divide" "Test string to first null"
# Python cannot print strings that contain the null (\0) character.
# For the purposes of this test, use repr()
gdb_py_test_silent_cmd "python nullst = nullst.string (length = 9)" "get string beyond null" 1
gdb_test "python print repr(nullst)" "u'divide\\\\x00et'"
}
# A few objfile tests.

View File

@ -2221,8 +2221,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;
@ -2238,6 +2239,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)
@ -2247,8 +2249,20 @@ value_get_print_value (struct value *value, enum varobj_display_formats format,
xfree (hint);
}
thevalue = apply_varobj_pretty_printer (value_formatter,
&replacement);
output = apply_varobj_pretty_printer (value_formatter,
&replacement);
if (output)
{
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);
Py_DECREF (py_str);
}
Py_DECREF (output);
}
if (thevalue && !string_print)
{
do_cleanups (back_to);
@ -2272,8 +2286,7 @@ value_get_print_value (struct value *value, enum varobj_display_formats format,
struct gdbarch *gdbarch = get_type_arch (value_type (value));
make_cleanup (xfree, thevalue);
LA_PRINT_STRING (stb, builtin_type (gdbarch)->builtin_char,
(gdb_byte *) thevalue, strlen (thevalue),
0, &opts);
thevalue, len, 0, &opts);
}
else
common_val_print (value, stb, 0, &opts, current_language);