Add gdb.Value.format_string ()

The str () function, called on a gdb.Value instance, produces a string
representation similar to what can be achieved with the print command,
but it doesn't allow to specify additional formatting settings, for
instance disabling pretty printers.

This patch introduces a new format_string () method to gdb.Value which
allows specifying more formatting options, thus giving access to more
features provided by the internal C function common_val_print ().

gdb/ChangeLog:

2019-04-01  Marco Barisione  <mbarisione@undo.io>

	Add gdb.Value.format_string ().
	* python/py-value.c (copy_py_bool_obj):
	(valpy_format_string): Add gdb.Value.format_string ().
	* NEWS: Document the addition of gdb.Value.format_string ().

gdb/doc/ChangeLog:

2019-04-01  Marco Barisione  <mbarisione@undo.io>

	* python.texi (Values From Inferior): Document
	gdb.Value.format_string ().

gdb/testsuite/ChangeLog:

2019-04-01  Marco Barisione  <mbarisione@undo.io>

	Test gdb.Value.format_string ().
	* gdb.python/py-format-string.exp: New test.
	* gdb.python/py-format-string.c: New file.
	* gdb.python/py-format-string.py: New file.
This commit is contained in:
Marco Barisione 2019-04-01 09:59:53 +02:00
parent 8828efdb24
commit 52093e1b93
6 changed files with 1377 additions and 0 deletions

View file

@ -588,6 +588,165 @@ valpy_string (PyObject *self, PyObject *args, PyObject *kw)
encoding, errors);
}
/* Given a Python object, copy its truth value to a C int (the value
pointed by dest).
If src_obj is NULL, then *dest is not modified.
Return true in case of success (including src_obj being NULL), false
in case of error. */
static bool
copy_py_bool_obj (int *dest, PyObject *src_obj)
{
if (src_obj)
{
int cmp = PyObject_IsTrue (src_obj);
if (cmp < 0)
return false;
*dest = cmp;
}
return true;
}
/* Implementation of gdb.Value.format_string (...) -> string.
Return Unicode string with value contents formatted using the
keyword-only arguments. */
static PyObject *
valpy_format_string (PyObject *self, PyObject *args, PyObject *kw)
{
static const char *keywords[] =
{
/* Basic C/C++ options. */
"raw", /* See the /r option to print. */
"pretty_arrays", /* See set print array on|off. */
"pretty_structs", /* See set print pretty on|off. */
"array_indexes", /* See set print array-indexes on|off. */
"symbols", /* See set print symbol on|off. */
"unions", /* See set print union on|off. */
/* C++ options. */
"deref_refs", /* No corresponding setting. */
"actual_objects", /* See set print object on|off. */
"static_members", /* See set print static-members on|off. */
/* C non-bool options. */
"max_elements", /* See set print elements N. */
"repeat_threshold", /* See set print repeats. */
"format", /* The format passed to the print command. */
NULL
};
/* This function has too many arguments to be useful as positionals, so
the user should specify them all as keyword arguments.
Python 3.3 and later have a way to specify it (both in C and Python
itself), but we could be compiled with older versions, so we just
check that the args tuple is empty. */
Py_ssize_t positional_count = PyObject_Length (args);
if (positional_count < 0)
return NULL;
else if (positional_count > 0)
{
/* This matches the error message that Python 3.3 raises when
passing positionals to functions expecting keyword-only
arguments. */
PyErr_Format (PyExc_TypeError,
"format_string() takes 0 positional arguments but %zu were given",
positional_count);
return NULL;
}
struct value_print_options opts;
get_user_print_options (&opts);
opts.deref_ref = 0;
/* We need objects for booleans as the "p" flag for bools is new in
Python 3.3. */
PyObject *raw_obj = NULL;
PyObject *pretty_arrays_obj = NULL;
PyObject *pretty_structs_obj = NULL;
PyObject *array_indexes_obj = NULL;
PyObject *symbols_obj = NULL;
PyObject *unions_obj = NULL;
PyObject *deref_refs_obj = NULL;
PyObject *actual_objects_obj = NULL;
PyObject *static_members_obj = NULL;
char *format = NULL;
if (!gdb_PyArg_ParseTupleAndKeywords (args,
kw,
"|O!O!O!O!O!O!O!O!O!IIs",
keywords,
&PyBool_Type, &raw_obj,
&PyBool_Type, &pretty_arrays_obj,
&PyBool_Type, &pretty_structs_obj,
&PyBool_Type, &array_indexes_obj,
&PyBool_Type, &symbols_obj,
&PyBool_Type, &unions_obj,
&PyBool_Type, &deref_refs_obj,
&PyBool_Type, &actual_objects_obj,
&PyBool_Type, &static_members_obj,
&opts.print_max,
&opts.repeat_count_threshold,
&format))
return NULL;
/* Set boolean arguments. */
if (!copy_py_bool_obj (&opts.raw, raw_obj))
return NULL;
if (!copy_py_bool_obj (&opts.prettyformat_arrays, pretty_arrays_obj))
return NULL;
if (!copy_py_bool_obj (&opts.prettyformat_structs, pretty_structs_obj))
return NULL;
if (!copy_py_bool_obj (&opts.print_array_indexes, array_indexes_obj))
return NULL;
if (!copy_py_bool_obj (&opts.symbol_print, symbols_obj))
return NULL;
if (!copy_py_bool_obj (&opts.unionprint, unions_obj))
return NULL;
if (!copy_py_bool_obj (&opts.deref_ref, deref_refs_obj))
return NULL;
if (!copy_py_bool_obj (&opts.objectprint, actual_objects_obj))
return NULL;
if (!copy_py_bool_obj (&opts.static_field_print, static_members_obj))
return NULL;
/* Numeric arguments for which 0 means unlimited (which we represent as
UINT_MAX). */
if (opts.print_max == 0)
opts.print_max = UINT_MAX;
if (opts.repeat_count_threshold == 0)
opts.repeat_count_threshold = UINT_MAX;
/* Other arguments. */
if (format != NULL)
{
if (strlen (format) == 1)
opts.format = format[0];
else
{
/* Mimic the message on standard Python ones for similar
errors. */
PyErr_SetString (PyExc_ValueError,
"a single character is required");
return NULL;
}
}
string_file stb;
TRY
{
common_val_print (((value_object *) self)->value, &stb, 0,
&opts, python_language);
}
CATCH (except, RETURN_MASK_ALL)
{
GDB_PY_HANDLE_EXCEPTION (except);
}
END_CATCH
return PyUnicode_Decode (stb.c_str (), stb.size (), host_charset (), NULL);
}
/* A helper function that implements the various cast operators. */
static PyObject *
@ -1944,6 +2103,11 @@ Return a lazy string representation of the value." },
Return Unicode string representation of the value." },
{ "fetch_lazy", valpy_fetch_lazy, METH_NOARGS,
"Fetches the value from the inferior, if it was lazy." },
{ "format_string", (PyCFunction) valpy_format_string,
METH_VARARGS | METH_KEYWORDS,
"format_string (...) -> string\n\
Return a string representation of the value using the specified\n\
formatting options" },
{NULL} /* Sentinel */
};