Message ID | DA4CEF9D-0714-4EA8-A08A-A3F02B923269@elemental.software |
---|---|
State | New, archived |
Headers |
Received: (qmail 3214 invoked by alias); 25 May 2017 02:33:46 -0000 Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: <gdb-patches.sourceware.org> List-Unsubscribe: <mailto:gdb-patches-unsubscribe-##L=##H@sourceware.org> List-Subscribe: <mailto:gdb-patches-subscribe@sourceware.org> List-Archive: <http://sourceware.org/ml/gdb-patches/> List-Post: <mailto:gdb-patches@sourceware.org> List-Help: <mailto:gdb-patches-help@sourceware.org>, <http://sourceware.org/ml/#faqs> Sender: gdb-patches-owner@sourceware.org Delivered-To: mailing list gdb-patches@sourceware.org Received: (qmail 3184 invoked by uid 89); 25 May 2017 02:33:45 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: =?ISO-8859-1?Q?No, score=-26.9 required=5.0 tests=BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, RP_MATCHES_RCVD, SPF_HELO_PASS, SPF_PASS autolearn=ham version=3.3.2 spammy=in-house, inhouse, isn, isn=e2?= X-HELO: smtp.elemental.software Received: from smtp.elemental.software (HELO smtp.elemental.software) (45.33.60.119) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Thu, 25 May 2017 02:33:43 +0000 Received: from [IPv6:2001:470:879a::d847:c47a:9f25:c1a] (unknown [IPv6:2001:470:879a:0:d847:c47a:9f25:c1a]) (Authenticated sender: peter@elemental.software) by smtp.elemental.software (Postfix) with ESMTPSA id D0079265DE for <gdb-patches@sourceware.org>; Wed, 24 May 2017 19:33:45 -0700 (PDT) From: Peter Linss <peter@elemental.software> Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable Mime-Version: 1.0 (Mac OS X Mail 10.3 \(3273\)) Subject: [PATCH] Fix usage of to_string() for pretty-printers with children Message-Id: <DA4CEF9D-0714-4EA8-A08A-A3F02B923269@elemental.software> Date: Wed, 24 May 2017 19:33:41 -0700 To: gdb-patches@sourceware.org |
Commit Message
Peter Linss
May 25, 2017, 2:33 a.m. UTC
Currently when using python pretty-printers that have children in the mi interpreter, the value of the variable object will always return “{...}”, this change will return the result of the pretty-printer’s to_string() method if present. If the pretty-printer has children but doesn’t have a to_string() method, then “{...}” will still be returned. This allows pretty-printers to optionally return a brief summary of the variable in addition to the expanded list of children and makes the behavior under the mi interpreter match that of the regular interpreter. This fixes bug 11335. I also removed the dynamic_varobj_has_child_method function as it wasn't doing anything that hadn’t already been done in the varobj_value_get_print_value function and isn’t used elsewhere. Tested with Eclipse and the libstdc++-v3 pretty-printer as well as custom pretty-printers for an in-house project and SublimeGDB (SublimeGDB required some additional changes to properly support pretty-printers but those are not related to this change). gdb/ChangeLog: * varobj.c (varobj_value_get_print_value): Call pretty-printer to_string method for value if present even when children method is available. (dynamic_varobj_has_child_method) Remove unused function. gdb/doc/ChangeLog: * gdb.texinfo (Variable Objects, Result): Update description of value to reflect to_string output. --- --
Comments
On 25/05/17 03:33, Peter Linss wrote: > gdb/ChangeLog: > > * varobj.c (varobj_value_get_print_value): Call pretty-printer > to_string method for value if present even when children > method is available. > (dynamic_varobj_has_child_method) Remove unused function. > > gdb/doc/ChangeLog: > > * gdb.texinfo (Variable Objects, Result): Update description of > value to reflect to_string output. Thanks. > > -#if HAVE_PYTHON > - > -static int > -dynamic_varobj_has_child_method (const struct varobj *var) > -{ > - PyObject *printer = var->dynamic->pretty_printer; > - > - if (!gdb_python_initialized) > - return 0; > - > - gdbpy_enter_varobj enter_py (var); > - return PyObject_HasAttr (printer, gdbpy_children_cst); > -} > -#endif > - In removing the above you are removing the Python environment call which, among other things, ensures the state of the Python GIL. The replacement hunk below does not make the same call? Is this intentional? > /* A factory for creating dynamic varobj's iterators. Returns an > iterator object suitable for iterating over VAR's children. */ > > @@ -2420,11 +2405,6 @@ varobj_value_get_print_value (struct value *value, > > if (value_formatter) > { > - /* First check to see if we have any children at all. If so, > - we simply return {...}. */ > - if (dynamic_varobj_has_child_method (var)) > - return "{...}"; > - > if (PyObject_HasAttr (value_formatter, gdbpy_to_string_cst)) > { > struct value *replacement; > @@ -2486,6 +2466,13 @@ varobj_value_get_print_value (struct value *value, > if (replacement) > value = replacement; > } > + else > + { > + /* If we don't have to_string but we have children, > + we simply return {...}. */ > + if (PyObject_HasAttr (value_formatter, gdbpy_children_cst)) > + return "{...}"; > + } You've removed a function but replaced it with an if (...) (and the associated safety calls). I'm not sure this is the right thing to do. Also, if the to_string call has changed, it might constitute an API change. And, alas, all changes need tests, unless obvious, and the outcome of this test is not obvious (well to me ;) ) Cheers Phil
> From: Peter Linss <peter@elemental.software> > Date: Wed, 24 May 2017 19:33:41 -0700 > > diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo > index 9fb70f6d2a..05e5b868ed 100644 > --- a/gdb/doc/gdb.texinfo > +++ b/gdb/doc/gdb.texinfo > @@ -29444,8 +29444,9 @@ reliable for a dynamic varobj. Instead, you must examine the > > @item value > The varobj's scalar value. For a varobj whose type is some sort of > -aggregate (e.g., a @code{struct}), or for a dynamic varobj, this value > -will not be interesting. > +aggregate (e.g., a @code{struct}) this value will not be interesting. ^ Please add back the comma removed here. The documentation part is approved with this gotcha fixed. Thanks.
> On May 25, 2017, at 3:06 AM, Phil Muldoon <pmuldoon@redhat.com> wrote: > > On 25/05/17 03:33, Peter Linss wrote: > > > >> gdb/ChangeLog: >> >> * varobj.c (varobj_value_get_print_value): Call pretty-printer >> to_string method for value if present even when children >> method is available. >> (dynamic_varobj_has_child_method) Remove unused function. >> >> gdb/doc/ChangeLog: >> >> * gdb.texinfo (Variable Objects, Result): Update description of >> value to reflect to_string output. > > Thanks. > >> >> -#if HAVE_PYTHON >> - >> -static int >> -dynamic_varobj_has_child_method (const struct varobj *var) >> -{ >> - PyObject *printer = var->dynamic->pretty_printer; >> - >> - if (!gdb_python_initialized) >> - return 0; >> - >> - gdbpy_enter_varobj enter_py (var); >> - return PyObject_HasAttr (printer, gdbpy_children_cst); >> -} >> -#endif >> - > > In removing the above you are removing the Python environment call > which, among other things, ensures the state of the Python GIL. The > replacement hunk below does not make the same call? Is this > intentional? Yes, see below. > > >> /* A factory for creating dynamic varobj's iterators. Returns an >> iterator object suitable for iterating over VAR's children. */ >> >> @@ -2420,11 +2405,6 @@ varobj_value_get_print_value (struct value *value, >> >> if (value_formatter) >> { >> - /* First check to see if we have any children at all. If so, >> - we simply return {...}. */ >> - if (dynamic_varobj_has_child_method (var)) >> - return "{...}"; >> - >> if (PyObject_HasAttr (value_formatter, gdbpy_to_string_cst)) >> { >> struct value *replacement; >> @@ -2486,6 +2466,13 @@ varobj_value_get_print_value (struct value *value, >> if (replacement) >> value = replacement; >> } >> + else >> + { >> + /* If we don't have to_string but we have children, >> + we simply return {...}. */ >> + if (PyObject_HasAttr (value_formatter, gdbpy_children_cst)) >> + return "{...}"; >> + } > > You've removed a function but replaced it with an if (...) (and the > associated safety calls). I'm not sure this is the right thing to do. As far as I could tell, everything done within the removed function was already done within the only function that called it. The gdb_python_initialized test is already performed on line 2400 (after the patch), pretty_printer is already copied form var->dynamic (line 2402), and there’s already a 'gdbpy_enter_varobj enter_py (var)’ on line 2404, which is still in scope. Aside from the actual call to PyObject_HasAttr(value_formatter, gdbpy_children_cst) everything in the function appeared redundant, and there’s also a call to PyObject_HasAttr(value_formatter, gdbpy_to_string_cst) on line 2408 which I presume is protected by the appropriate safety calls. If I’m missing something, it would be trivial to leave the dynamic_varobj_has_child_method function and call it instead of PyObject_HasAttr, the necessary change here is shifting the logic so that to_string always gets called if present, and the default return value of “{...}” only gets returned if there isn’t a to_string method on the pretty-printer, everything else is just cleanup. > > Also, if the to_string call has changed, it might constitute an API > change. Not sure what you mean here, nothing in the call to to_string has changed, only that it will always be called if it’s present, where previously the call to to_string would be skipped if the pretty-printer has a children method. Note that this is the same behavior when using a pretty printer in the regular interpreter, so pretty-printer authors should already be aware of it. > > And, alas, all changes need tests, unless obvious, and the outcome of > this test is not obvious (well to me ;) ) I looked for tests involving pretty-printers and didn’t find any, and I have no idea how to integrate a pretty-printer into the testing environment, if there’s something you can point me to I’d be happy to write (or modify) a test as needed. FWIW I did test this both under Eclipse, SublimeGDB, and manually running the mi interpreter (though I, of course, understand the value of automated testing). The only change this introduces is when inspecting pretty-printed variables in a gdb UI, rather than the current behavior of always seeing “{...}” for the value of variables that have children, if the pretty-printer is returning a summary value in to_string (like an item count for a list) then that value is available to the GUI via the mi interpreter (as it would currently be displayed if the variable was printed in the regular interpreter). And thanks for the prompt review, Peter > > Cheers > > Phil
> On May 25, 2017, at 10:42 AM, Peter Linss <peter@elemental.software> wrote: > >> >> On May 25, 2017, at 3:06 AM, Phil Muldoon <pmuldoon@redhat.com> wrote: >> >> On 25/05/17 03:33, Peter Linss wrote: >> >> >> >>> gdb/ChangeLog: >>> >>> * varobj.c (varobj_value_get_print_value): Call pretty-printer >>> to_string method for value if present even when children >>> method is available. >>> (dynamic_varobj_has_child_method) Remove unused function. >>> >>> gdb/doc/ChangeLog: >>> >>> * gdb.texinfo (Variable Objects, Result): Update description of >>> value to reflect to_string output. >> >> Thanks. >> >>> >>> -#if HAVE_PYTHON >>> - >>> -static int >>> -dynamic_varobj_has_child_method (const struct varobj *var) >>> -{ >>> - PyObject *printer = var->dynamic->pretty_printer; >>> - >>> - if (!gdb_python_initialized) >>> - return 0; >>> - >>> - gdbpy_enter_varobj enter_py (var); >>> - return PyObject_HasAttr (printer, gdbpy_children_cst); >>> -} >>> -#endif >>> - >> >> In removing the above you are removing the Python environment call >> which, among other things, ensures the state of the Python GIL. The >> replacement hunk below does not make the same call? Is this >> intentional? > > Yes, see below. > >> >> >>> /* A factory for creating dynamic varobj's iterators. Returns an >>> iterator object suitable for iterating over VAR's children. */ >>> >>> @@ -2420,11 +2405,6 @@ varobj_value_get_print_value (struct value *value, >>> >>> if (value_formatter) >>> { >>> - /* First check to see if we have any children at all. If so, >>> - we simply return {...}. */ >>> - if (dynamic_varobj_has_child_method (var)) >>> - return "{...}"; >>> - >>> if (PyObject_HasAttr (value_formatter, gdbpy_to_string_cst)) >>> { >>> struct value *replacement; >>> @@ -2486,6 +2466,13 @@ varobj_value_get_print_value (struct value *value, >>> if (replacement) >>> value = replacement; >>> } >>> + else >>> + { >>> + /* If we don't have to_string but we have children, >>> + we simply return {...}. */ >>> + if (PyObject_HasAttr (value_formatter, gdbpy_children_cst)) >>> + return "{...}"; >>> + } >> >> You've removed a function but replaced it with an if (...) (and the >> associated safety calls). I'm not sure this is the right thing to do. > > As far as I could tell, everything done within the removed function was already done within the only function that called it. > The gdb_python_initialized test is already performed on line 2400 (after the patch), pretty_printer is already copied form var->dynamic (line 2402), and there’s already a 'gdbpy_enter_varobj enter_py (var)’ on line 2404, which is still in scope. > Aside from the actual call to PyObject_HasAttr(value_formatter, gdbpy_children_cst) everything in the function appeared redundant, and there’s also a call to PyObject_HasAttr(value_formatter, gdbpy_to_string_cst) on line 2408 which I presume is protected by the appropriate safety calls. > > If I’m missing something, it would be trivial to leave the dynamic_varobj_has_child_method function and call it instead of PyObject_HasAttr, the necessary change here is shifting the logic so that to_string always gets called if present, and the default return value of “{...}” only gets returned if there isn’t a to_string method on the pretty-printer, everything else is just cleanup. > >> >> Also, if the to_string call has changed, it might constitute an API >> change. > > Not sure what you mean here, nothing in the call to to_string has changed, only that it will always be called if it’s present, where previously the call to to_string would be skipped if the pretty-printer has a children method. Note that this is the same behavior when using a pretty printer in the regular interpreter, so pretty-printer authors should already be aware of it. > >> >> And, alas, all changes need tests, unless obvious, and the outcome of >> this test is not obvious (well to me ;) ) > > I looked for tests involving pretty-printers and didn’t find any, and I have no idea how to integrate a pretty-printer into the testing environment, if there’s something you can point me to I’d be happy to write (or modify) a test as needed. FWIW I did test this both under Eclipse, SublimeGDB, and manually running the mi interpreter (though I, of course, understand the value of automated testing). > > The only change this introduces is when inspecting pretty-printed variables in a gdb UI, rather than the current behavior of always seeing “{...}” for the value of variables that have children, if the pretty-printer is returning a summary value in to_string (like an item count for a list) then that value is available to the GUI via the mi interpreter (as it would currently be displayed if the variable was printed in the regular interpreter). > > And thanks for the prompt review, > > Peter > >> >> Cheers >> >> Phil Ping.
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo index 9fb70f6d2a..05e5b868ed 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -29444,8 +29444,9 @@ reliable for a dynamic varobj. Instead, you must examine the @item value The varobj's scalar value. For a varobj whose type is some sort of -aggregate (e.g., a @code{struct}), or for a dynamic varobj, this value -will not be interesting. +aggregate (e.g., a @code{struct}) this value will not be interesting. +For a dynamic varobj, this value comes from the Python pretty-printer +object's @code{to_string} method, if present. @xref{Pretty Printing API}. @item type The varobj's type. This is a string representation of the type, as diff --git a/gdb/varobj.c b/gdb/varobj.c index 7bd549d45c..925c6318a8 100644 --- a/gdb/varobj.c +++ b/gdb/varobj.c @@ -686,21 +686,6 @@ install_dynamic_child (struct varobj *var, } } -#if HAVE_PYTHON - -static int -dynamic_varobj_has_child_method (const struct varobj *var) -{ - PyObject *printer = var->dynamic->pretty_printer; - - if (!gdb_python_initialized) - return 0; - - gdbpy_enter_varobj enter_py (var); - return PyObject_HasAttr (printer, gdbpy_children_cst); -} -#endif - /* A factory for creating dynamic varobj's iterators. Returns an iterator object suitable for iterating over VAR's children. */ @@ -2420,11 +2405,6 @@ varobj_value_get_print_value (struct value *value, if (value_formatter) { - /* First check to see if we have any children at all. If so, - we simply return {...}. */ - if (dynamic_varobj_has_child_method (var)) - return "{...}"; - if (PyObject_HasAttr (value_formatter, gdbpy_to_string_cst)) { struct value *replacement; @@ -2486,6 +2466,13 @@ varobj_value_get_print_value (struct value *value, if (replacement) value = replacement; } + else + { + /* If we don't have to_string but we have children, + we simply return {...}. */ + if (PyObject_HasAttr (value_formatter, gdbpy_children_cst)) + return "{...}"; + } } } #endif