mirror of
https://sourceware.org/git/binutils-gdb.git
synced 2025-02-23 13:21:43 +08:00
Expose current 'print' settings to Python
PR python/17291 asks for access to the current print options. While I think this need is largely satisfied by the existence of Value.format_string, it seemed to me that a bit more could be done. First, while Value.format_string uses the user's settings, it does not react to temporary settings such as "print/x". This patch changes this. Second, there is no good way to examine the current settings (in particular the temporary ones in effect for just a single "print"). This patch adds this as well. Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=17291
This commit is contained in:
parent
aa63b0a77e
commit
c4a3dbaf11
7
gdb/NEWS
7
gdb/NEWS
@ -149,6 +149,13 @@ GNU/Linux/LoongArch (gdbserver) loongarch*-*-linux*
|
||||
** gdb.Objfile now has an attribute named "is_file". This is True
|
||||
if the objfile comes from a file, and False otherwise.
|
||||
|
||||
** New function gdb.print_options that returns a dictionary of the
|
||||
prevailing print options, in the form accepted by
|
||||
gdb.Value.format_string.
|
||||
|
||||
** gdb.Value.format_string now uses the format provided by 'print',
|
||||
if it is called during a 'print' or other similar operation.
|
||||
|
||||
* New features in the GDB remote stub, GDBserver
|
||||
|
||||
** GDBserver is now supported on LoongArch GNU/Linux.
|
||||
|
@ -1742,6 +1742,24 @@ pretty-printer for this value exists, then it is returned. If no such
|
||||
printer exists, then this returns @code{None}.
|
||||
@end defun
|
||||
|
||||
Normally, a pretty-printer can respect the user's print settings
|
||||
(including temporarily applied settings, such as @samp{/x}) simply by
|
||||
calling @code{Value.format_string} (@pxref{Values From Inferior}).
|
||||
However, these settings can also be queried directly:
|
||||
|
||||
@findex gdb.print_options
|
||||
@defun gdb.print_options ()
|
||||
Return a dictionary whose keys are the valid keywords that can be
|
||||
given to @code{Value.format_string}, and whose values are the user's
|
||||
settings. During a @code{print} or other operation, the values will
|
||||
reflect any flags that are temporarily in effect.
|
||||
|
||||
@smallexample
|
||||
(gdb) python print (gdb.print_options ()['max_elements'])
|
||||
200
|
||||
@end smallexample
|
||||
@end defun
|
||||
|
||||
@node Selecting Pretty-Printers
|
||||
@subsubsection Selecting Pretty-Printers
|
||||
@cindex selecting python pretty-printers
|
||||
|
@ -39,6 +39,10 @@ enum gdbpy_string_repr_result
|
||||
string_repr_ok
|
||||
};
|
||||
|
||||
/* If non-null, points to options that are in effect while
|
||||
printing. */
|
||||
const struct value_print_options *gdbpy_current_print_options;
|
||||
|
||||
/* Helper function for find_pretty_printer which iterates over a list,
|
||||
calls each function and inspects output. This will return a
|
||||
printer object if one recognizes VALUE. If no printer is found, it
|
||||
@ -604,6 +608,9 @@ gdbpy_apply_val_pretty_printer (const struct extension_language_defn *extlang,
|
||||
if (printer == Py_None)
|
||||
return EXT_LANG_RC_NOP;
|
||||
|
||||
scoped_restore set_options = make_scoped_restore (&gdbpy_current_print_options,
|
||||
options);
|
||||
|
||||
/* If we are printing a map, we want some special formatting. */
|
||||
gdb::unique_xmalloc_ptr<char> hint (gdbpy_get_display_hint (printer.get ()));
|
||||
|
||||
@ -632,8 +639,12 @@ gdbpy_apply_val_pretty_printer (const struct extension_language_defn *extlang,
|
||||
gdbpy_ref<>
|
||||
apply_varobj_pretty_printer (PyObject *printer_obj,
|
||||
struct value **replacement,
|
||||
struct ui_file *stream)
|
||||
struct ui_file *stream,
|
||||
const value_print_options *opts)
|
||||
{
|
||||
scoped_restore set_options = make_scoped_restore (&gdbpy_current_print_options,
|
||||
opts);
|
||||
|
||||
*replacement = NULL;
|
||||
gdbpy_ref<> py_str = pretty_print_one_value (printer_obj, replacement);
|
||||
|
||||
@ -688,3 +699,88 @@ gdbpy_default_visualizer (PyObject *self, PyObject *args)
|
||||
|
||||
return find_pretty_printer (val_obj).release ();
|
||||
}
|
||||
|
||||
/* Helper function to set a boolean in a dictionary. */
|
||||
static int
|
||||
set_boolean (PyObject *dict, const char *name, bool val)
|
||||
{
|
||||
gdbpy_ref<> val_obj (PyBool_FromLong (val));
|
||||
if (val_obj == nullptr)
|
||||
return -1;
|
||||
return PyDict_SetItemString (dict, name, val_obj.get ());
|
||||
}
|
||||
|
||||
/* Helper function to set an integer in a dictionary. */
|
||||
static int
|
||||
set_unsigned (PyObject *dict, const char *name, unsigned int val)
|
||||
{
|
||||
gdbpy_ref<> val_obj = gdb_py_object_from_ulongest (val);
|
||||
if (val_obj == nullptr)
|
||||
return -1;
|
||||
return PyDict_SetItemString (dict, name, val_obj.get ());
|
||||
}
|
||||
|
||||
/* Implement gdb.print_options. */
|
||||
PyObject *
|
||||
gdbpy_print_options (PyObject *unused1, PyObject *unused2)
|
||||
{
|
||||
gdbpy_ref<> result (PyDict_New ());
|
||||
if (result == nullptr)
|
||||
return nullptr;
|
||||
|
||||
value_print_options opts;
|
||||
gdbpy_get_print_options (&opts);
|
||||
|
||||
if (set_boolean (result.get (), "raw",
|
||||
opts.raw) < 0
|
||||
|| set_boolean (result.get (), "pretty_arrays",
|
||||
opts.prettyformat_arrays) < 0
|
||||
|| set_boolean (result.get (), "pretty_structs",
|
||||
opts.prettyformat_structs) < 0
|
||||
|| set_boolean (result.get (), "array_indexes",
|
||||
opts.print_array_indexes) < 0
|
||||
|| set_boolean (result.get (), "symbols",
|
||||
opts.symbol_print) < 0
|
||||
|| set_boolean (result.get (), "unions",
|
||||
opts.unionprint) < 0
|
||||
|| set_boolean (result.get (), "address",
|
||||
opts.addressprint) < 0
|
||||
|| set_boolean (result.get (), "deref_refs",
|
||||
opts.deref_ref) < 0
|
||||
|| set_boolean (result.get (), "actual_objects",
|
||||
opts.objectprint) < 0
|
||||
|| set_boolean (result.get (), "static_members",
|
||||
opts.static_field_print) < 0
|
||||
|| set_boolean (result.get (), "deref_refs",
|
||||
opts.deref_ref) < 0
|
||||
|| set_unsigned (result.get (), "max_elements",
|
||||
opts.print_max) < 0
|
||||
|| set_unsigned (result.get (), "max_depth",
|
||||
opts.max_depth) < 0
|
||||
|| set_unsigned (result.get (), "repeat_threshold",
|
||||
opts.repeat_count_threshold) < 0)
|
||||
return nullptr;
|
||||
|
||||
if (opts.format != 0)
|
||||
{
|
||||
char str[2] = { (char) opts.format, 0 };
|
||||
gdbpy_ref<> fmtstr = host_string_to_python_string (str);
|
||||
if (fmtstr == nullptr)
|
||||
return nullptr;
|
||||
if (PyDict_SetItemString (result.get (), "format", fmtstr.get ()) < 0)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return result.release ();
|
||||
}
|
||||
|
||||
/* Helper function that either finds the prevailing print options, or
|
||||
calls get_user_print_options. */
|
||||
void
|
||||
gdbpy_get_print_options (value_print_options *opts)
|
||||
{
|
||||
if (gdbpy_current_print_options != nullptr)
|
||||
*opts = *gdbpy_current_print_options;
|
||||
else
|
||||
get_user_print_options (opts);
|
||||
}
|
||||
|
@ -673,7 +673,7 @@ valpy_format_string (PyObject *self, PyObject *args, PyObject *kw)
|
||||
}
|
||||
|
||||
struct value_print_options opts;
|
||||
get_user_print_options (&opts);
|
||||
gdbpy_get_print_options (&opts);
|
||||
opts.deref_ref = 0;
|
||||
|
||||
/* We need objects for booleans as the "p" flag for bools is new in
|
||||
@ -1163,7 +1163,7 @@ valpy_str (PyObject *self)
|
||||
{
|
||||
struct value_print_options opts;
|
||||
|
||||
get_user_print_options (&opts);
|
||||
gdbpy_get_print_options (&opts);
|
||||
opts.deref_ref = 0;
|
||||
|
||||
string_file stb;
|
||||
|
@ -17,13 +17,15 @@
|
||||
#include "python-internal.h"
|
||||
#include "varobj.h"
|
||||
#include "varobj-iter.h"
|
||||
#include "valprint.h"
|
||||
|
||||
/* A dynamic varobj iterator "class" for python pretty-printed
|
||||
varobjs. This inherits struct varobj_iter. */
|
||||
|
||||
struct py_varobj_iter : public varobj_iter
|
||||
{
|
||||
py_varobj_iter (struct varobj *var, gdbpy_ref<> &&pyiter);
|
||||
py_varobj_iter (struct varobj *var, gdbpy_ref<> &&pyiter,
|
||||
const value_print_options *opts);
|
||||
~py_varobj_iter () override;
|
||||
|
||||
std::unique_ptr<varobj_item> next () override;
|
||||
@ -41,6 +43,9 @@ struct py_varobj_iter : public varobj_iter
|
||||
/* The python iterator returned by the printer's 'children' method,
|
||||
or NULL if not available. */
|
||||
PyObject *m_iter;
|
||||
|
||||
/* The print options to use. */
|
||||
value_print_options m_opts;
|
||||
};
|
||||
|
||||
/* Implementation of the 'dtor' method of pretty-printed varobj
|
||||
@ -67,6 +72,9 @@ py_varobj_iter::next ()
|
||||
|
||||
gdbpy_enter_varobj enter_py (m_var);
|
||||
|
||||
scoped_restore set_options = make_scoped_restore (&gdbpy_current_print_options,
|
||||
&m_opts);
|
||||
|
||||
gdbpy_ref<> item (PyIter_Next (m_iter));
|
||||
|
||||
if (item == NULL)
|
||||
@ -124,9 +132,11 @@ py_varobj_iter::next ()
|
||||
whose children the iterator will be iterating over. PYITER is the
|
||||
python iterator actually responsible for the iteration. */
|
||||
|
||||
py_varobj_iter::py_varobj_iter (struct varobj *var, gdbpy_ref<> &&pyiter)
|
||||
py_varobj_iter::py_varobj_iter (struct varobj *var, gdbpy_ref<> &&pyiter,
|
||||
const value_print_options *opts)
|
||||
: m_var (var),
|
||||
m_iter (pyiter.release ())
|
||||
m_iter (pyiter.release ()),
|
||||
m_opts (*opts)
|
||||
{
|
||||
}
|
||||
|
||||
@ -134,13 +144,17 @@ py_varobj_iter::py_varobj_iter (struct varobj *var, gdbpy_ref<> &&pyiter)
|
||||
over VAR's children. */
|
||||
|
||||
std::unique_ptr<varobj_iter>
|
||||
py_varobj_get_iterator (struct varobj *var, PyObject *printer)
|
||||
py_varobj_get_iterator (struct varobj *var, PyObject *printer,
|
||||
const value_print_options *opts)
|
||||
{
|
||||
gdbpy_enter_varobj enter_py (var);
|
||||
|
||||
if (!PyObject_HasAttr (printer, gdbpy_children_cst))
|
||||
return NULL;
|
||||
|
||||
scoped_restore set_options = make_scoped_restore (&gdbpy_current_print_options,
|
||||
opts);
|
||||
|
||||
gdbpy_ref<> children (PyObject_CallMethodObjArgs (printer, gdbpy_children_cst,
|
||||
NULL));
|
||||
if (children == NULL)
|
||||
@ -157,5 +171,6 @@ py_varobj_get_iterator (struct varobj *var, PyObject *printer)
|
||||
}
|
||||
|
||||
return std::unique_ptr<varobj_iter> (new py_varobj_iter (var,
|
||||
std::move (iter)));
|
||||
std::move (iter),
|
||||
opts));
|
||||
}
|
||||
|
@ -746,11 +746,16 @@ int gdbpy_is_value_object (PyObject *obj);
|
||||
other pretty-printer functions, because they refer to PyObject. */
|
||||
gdbpy_ref<> apply_varobj_pretty_printer (PyObject *print_obj,
|
||||
struct value **replacement,
|
||||
struct ui_file *stream);
|
||||
struct ui_file *stream,
|
||||
const value_print_options *opts);
|
||||
gdbpy_ref<> gdbpy_get_varobj_pretty_printer (struct value *value);
|
||||
gdb::unique_xmalloc_ptr<char> gdbpy_get_display_hint (PyObject *printer);
|
||||
PyObject *gdbpy_default_visualizer (PyObject *self, PyObject *args);
|
||||
|
||||
PyObject *gdbpy_print_options (PyObject *self, PyObject *args);
|
||||
void gdbpy_get_print_options (value_print_options *opts);
|
||||
extern const struct value_print_options *gdbpy_current_print_options;
|
||||
|
||||
void bpfinishpy_pre_stop_hook (struct gdbpy_breakpoint_object *bp_obj);
|
||||
void bpfinishpy_post_stop_hook (struct gdbpy_breakpoint_object *bp_obj);
|
||||
|
||||
@ -784,8 +789,10 @@ int gdb_pymodule_addobject (PyObject *module, const char *name,
|
||||
|
||||
struct varobj_iter;
|
||||
struct varobj;
|
||||
std::unique_ptr<varobj_iter> py_varobj_get_iterator (struct varobj *var,
|
||||
PyObject *printer);
|
||||
std::unique_ptr<varobj_iter> py_varobj_get_iterator
|
||||
(struct varobj *var,
|
||||
PyObject *printer,
|
||||
const value_print_options *opts);
|
||||
|
||||
/* Deleter for Py_buffer unique_ptr specialization. */
|
||||
|
||||
|
@ -2560,6 +2560,10 @@ the returned string is 'ADDRESS <SYMBOL+OFFSET>' without the quotes." },
|
||||
"current_language () -> string\n\
|
||||
Return the name of the currently selected language." },
|
||||
|
||||
{ "print_options", gdbpy_print_options, METH_NOARGS,
|
||||
"print_options () -> dict\n\
|
||||
Return the current print options." },
|
||||
|
||||
{NULL, NULL, 0, NULL}
|
||||
};
|
||||
|
||||
|
@ -544,10 +544,12 @@ proc_with_prefix test_nibbles {} {
|
||||
"0010 1010" \
|
||||
"42 with option ${opts}"
|
||||
|
||||
check_format_string "a_point_t" $opts
|
||||
check_format_string "a_point_t" $opts \
|
||||
[string_to_regexp "Pretty Point (0010 1010, 1100)"]
|
||||
check_format_string "a_point_t_pointer" $opts \
|
||||
$binary_pointer_regexp
|
||||
check_format_string "another_point" $opts
|
||||
check_format_string "another_point" $opts \
|
||||
[string_to_regexp "Pretty Point (0111 1011, 0001 1100 1000)"]
|
||||
|
||||
check_format_string "a_struct_with_union" $opts \
|
||||
"\\{the_union = \\{an_int = 0010 1010 0010 1010 0010 1010 0010 1010, a_char = 0010 1010\\}\\}"
|
||||
@ -574,10 +576,12 @@ proc_with_prefix test_nibbles {} {
|
||||
"0010'1010" \
|
||||
"42 with option ${opts}"
|
||||
|
||||
check_format_string "a_point_t" $opts
|
||||
check_format_string "a_point_t" $opts \
|
||||
[string_to_regexp "Pretty Point (0010'1010, 1100)"]
|
||||
check_format_string "a_point_t_pointer" $opts \
|
||||
$binary_pointer_regexp
|
||||
check_format_string "another_point" $opts
|
||||
check_format_string "another_point" $opts \
|
||||
[string_to_regexp "Pretty Point (0111'1011, 0001'1100'1000)"]
|
||||
|
||||
check_format_string "a_struct_with_union" $opts \
|
||||
"\\{the_union = \\{an_int = 0010'1010'0010'1010'0010'1010'0010'1010, a_char = 0010'1010\\}\\}"
|
||||
@ -598,7 +602,8 @@ proc_with_prefix test_nibbles {} {
|
||||
check_format_string "a_symbol_pointer" $opts \
|
||||
$binary_pointer_regexp
|
||||
|
||||
check_format_string "a_point_t_ref" $opts
|
||||
check_format_string "a_point_t_ref" $opts \
|
||||
[string_to_regexp "Pretty Point (0010'1010, 1100)"]
|
||||
check_format_string "a_base_ref" $opts
|
||||
}
|
||||
}
|
||||
@ -938,9 +943,11 @@ proc_with_prefix test_format {} {
|
||||
"0x2a" \
|
||||
"42 with option ${opts}"
|
||||
|
||||
check_format_string "a_point_t" $opts
|
||||
check_format_string "a_point_t" $opts \
|
||||
"Pretty Point \\(0x2a, 0xc\\)"
|
||||
check_format_string "a_point_t_pointer" $opts
|
||||
check_format_string "another_point" $opts
|
||||
check_format_string "another_point" $opts \
|
||||
"Pretty Point \\(0x7b, 0x1c8\\)"
|
||||
check_format_string "a_struct_with_union" $opts \
|
||||
"\\{the_union = \\{an_int = 0x2a2a2a2a, a_char = 0x2a\\}\\}"
|
||||
check_format_string "an_enum" $opts \
|
||||
@ -961,7 +968,8 @@ proc_with_prefix test_format {} {
|
||||
$default_pointer_regexp
|
||||
|
||||
if { $current_lang == "c++" } {
|
||||
check_format_string "a_point_t_ref" $opts
|
||||
check_format_string "a_point_t_ref" $opts \
|
||||
"Pretty Point \\(0x2a, 0xc\\)"
|
||||
check_format_string "a_base_ref" $opts
|
||||
}
|
||||
}
|
||||
@ -974,10 +982,12 @@ proc_with_prefix test_format {} {
|
||||
"101010" \
|
||||
"42 with option ${opts}"
|
||||
|
||||
check_format_string "a_point_t" $opts
|
||||
check_format_string "a_point_t" $opts \
|
||||
"Pretty Point \\(101010, 1100\\)"
|
||||
check_format_string "a_point_t_pointer" $opts \
|
||||
$binary_pointer_regexp
|
||||
check_format_string "another_point" $opts
|
||||
check_format_string "another_point" $opts \
|
||||
"Pretty Point \\(1111011, 111001000\\)"
|
||||
check_format_string "a_struct_with_union" $opts \
|
||||
"\\{the_union = \\{an_int = 101010001010100010101000101010, a_char = 101010\\}\\}"
|
||||
check_format_string "an_enum" $opts \
|
||||
@ -998,7 +1008,8 @@ proc_with_prefix test_format {} {
|
||||
$binary_pointer_regexp
|
||||
|
||||
if { $current_lang == "c++" } {
|
||||
check_format_string "a_point_t_ref" $opts
|
||||
check_format_string "a_point_t_ref" $opts \
|
||||
"Pretty Point \\(101010, 1100\\)"
|
||||
check_format_string "a_base_ref" $opts
|
||||
}
|
||||
}
|
||||
@ -1103,6 +1114,21 @@ proc test_styling {} {
|
||||
"{[style x variable] = 42, [style y variable] = 12}"
|
||||
}
|
||||
|
||||
# Test the gdb.print_options API.
|
||||
proc test_print_options {} {
|
||||
gdb_test_no_output "set print elements 500"
|
||||
gdb_test "python print(gdb.print_options()\['max_elements'\])" "500" \
|
||||
"examine max elements"
|
||||
gdb_test "python print('format' in gdb.print_options())" "False" \
|
||||
"examine format"
|
||||
|
||||
check_format_string "a_point_t" "format='t'" \
|
||||
"Pretty Point \\(101010, 1100\\)" \
|
||||
"print in binary to fetch options"
|
||||
gdb_test "python print(saved_options\['format'\] == 't')" "True" \
|
||||
"format was set"
|
||||
}
|
||||
|
||||
# Run all the tests in common for both C and C++.
|
||||
proc_with_prefix test_all_common {} {
|
||||
# No options.
|
||||
@ -1127,6 +1153,7 @@ proc_with_prefix test_all_common {} {
|
||||
test_mixed
|
||||
# Various error conditions.
|
||||
test_invalid_args
|
||||
test_print_options
|
||||
}
|
||||
|
||||
# The current language ("c" or "c++" while running tests).
|
||||
|
@ -18,12 +18,16 @@
|
||||
|
||||
import gdb
|
||||
|
||||
saved_options = {}
|
||||
|
||||
|
||||
class PointPrinter(object):
|
||||
def __init__(self, val):
|
||||
self.val = val
|
||||
|
||||
def to_string(self):
|
||||
global saved_options
|
||||
saved_options = gdb.print_options()
|
||||
return "Pretty Point (%s, %s)" % (self.val["x"], self.val["y"])
|
||||
|
||||
|
||||
|
13
gdb/varobj.c
13
gdb/varobj.c
@ -658,7 +658,11 @@ varobj_get_iterator (struct varobj *var)
|
||||
{
|
||||
#if HAVE_PYTHON
|
||||
if (var->dynamic->pretty_printer)
|
||||
return py_varobj_get_iterator (var, var->dynamic->pretty_printer);
|
||||
{
|
||||
value_print_options opts;
|
||||
varobj_formatted_print_options (&opts, var->format);
|
||||
return py_varobj_get_iterator (var, var->dynamic->pretty_printer, &opts);
|
||||
}
|
||||
#endif
|
||||
|
||||
gdb_assert_not_reached ("requested an iterator from a non-dynamic varobj");
|
||||
@ -2146,6 +2150,8 @@ varobj_value_get_print_value (struct value *value,
|
||||
string_file stb;
|
||||
std::string thevalue;
|
||||
|
||||
varobj_formatted_print_options (&opts, format);
|
||||
|
||||
#if HAVE_PYTHON
|
||||
if (gdb_python_initialized)
|
||||
{
|
||||
@ -2166,7 +2172,8 @@ varobj_value_get_print_value (struct value *value,
|
||||
|
||||
gdbpy_ref<> output = apply_varobj_pretty_printer (value_formatter,
|
||||
&replacement,
|
||||
&stb);
|
||||
&stb,
|
||||
&opts);
|
||||
|
||||
/* If we have string like output ... */
|
||||
if (output != NULL)
|
||||
@ -2225,8 +2232,6 @@ varobj_value_get_print_value (struct value *value,
|
||||
}
|
||||
#endif
|
||||
|
||||
varobj_formatted_print_options (&opts, format);
|
||||
|
||||
/* If the THEVALUE has contents, it is a regular string. */
|
||||
if (!thevalue.empty ())
|
||||
current_language->printstr (&stb, type, (gdb_byte *) thevalue.c_str (),
|
||||
|
Loading…
Reference in New Issue
Block a user