Vladislav Ivanishin <v...@ispras.ru> writes:

> David Malcolm <dmalc...@redhat.com> writes:
>
>> On Tue, 2019-07-02 at 14:29 +0300, Vladislav Ivanishin wrote:
>>> David Malcolm <dmalc...@redhat.com> writes:
>>> 
>>> > On Mon, 2019-07-01 at 12:50 +0300, Vladislav Ivanishin wrote:
>>> > > Hi!
>>> > > 
>>> > > GDB's Python API provides strip_typedefs method that can be
>>> > > instrumental for writing DRY code.  Using it at least partially
>>> > > obviates the need for the add_printer_for_types method we have in
>>> > > gdbhooks.py (it takes a list of typenames to match and is usually
>>> > > used to deal with typedefs).
>>> > > 
>>> > > I think, the code can be simplified further (there's still
>>> > > ['tree_node *', 'const tree_node *'], which is a little awkward)
>>> > > if we deal with pointer types in a uniform fashion (I'll touch on
>>> > > this in the description of the second patch).  But that can be
>>> > > improved separately.
>>> > > 
>>> > > The gimple_statement_cond, etc. part has been dysfunctional for a
>>> > > while (namely since gimple-classes-v2-option-3 branch was
>>> > > merged).  I updated it to use the new classes' names.  That seems
>>> > > to work (though it doesn't output much info anyway: pretty
>>> > >        <gimple_phi 0x7ffff78c0200> vs. 
>>> > >        (gphi *) 0x7ffff78c0200
>>> > > in the raw version).
>>> > > 
>>> > > I changed the name passed to pp.add_printer_for_types() for
>>> > > scalar_mode and friends -- so they all share the same name now --
>>> > > but I don't believe the name is used in any context where it
>>> > > would matter.
>>> > 
>>> > IIRC there's a gdb command to tell you what the registered pretty-
>>> > printers are;
>>> 
>>> Yeah, it's (gdb) info pretty-printer
>>> 
>>> > I think the name is only ever used in that context (or maybe for
>>> > fine-grained control of pretty-printing) -
>>> 
>>> From the gdb info manual:
>>> 'disable pretty-printer [OBJECT-REGEXP [NAME-REGEXP]]'
>>>      Disable pretty-printers matching OBJECT-REGEXP and NAME-REGEXP.
>>> 
>>> In our case, this is how to do it:
>>>     (gdb) disable pretty-printer global gcc;scalar.*
>>> 
>>> So, that would be a regression, if different modes were given
>>> different names on purpose (starts with r251467).  Looks
>>> unintentional though, and the subprinter is very simple.
>>> 
>>> I think, these scenarios exhaust the uses for the name attribute of a
>>> pretty printer.
>>> 
>>> > and I don't know of anyone who uses that.  I don't think changing
>>> > the name matters.
>>> 
>>> Good.  Neither do I :) Except after writing this I started using this
>>> feature myself.  It provides a convenient way to isolate a faulty
>>> pretty-printer, or continue debugging without it.  The manual says
>>> that "The consequences of a broken pretty-printer are severe enough
>>> that GDB provides support for enabling and disabling individual
>>> printers".  Oh, were they right ...  (see below).
>>
>> In any case, I have no objection to the change-of-names part of the
>> patch.
>>
>>> > > This is just a clean up of gdbhooks.py.  OK to commit?
>>> > 
>>> > The only area I wasn't sure about were the removal hunks relating
>>> > to machine modes: is that all covered now by the looking-through-
>>> > typedefs?
>>> 
>>> Yes, I checked (using debug output) that all the modes for which I
>>> removed explicit handling are correctly expanded to either
>>> opt_mode<>, or pod_mode<>.
>>> 
>>> > Otherwise, looks good to me.  I assume you've tested the patch by
>>> > debugging with it.
>>> 
>>> Yeah, I thought my debugging with the patch should have given it
>>> reasonable coverage.
>>> 
>>> However, I had not previously actually tested debugging code
>>> involving modes, so I went ahead and did it.  And I am seeing a
>>> segfault with RtxPrinter now (-ex "b reg_nonzero_bits_for_combine"
>>> -ex "r" -ex "bt").  Delving in...
>>> 
>>> The rtx type (for which the unqualified form is also 'rtx') was not
>>> being matched by any of the printers.  The typedef-stripped form is
>>> 'rtx_def *'. It matches now and uncovers a bug in the subprinter(?)
>>> 
>>> I dug into it and the impression I have so far is that the
>>> print_inline_rtx call upsets gdb's frame unwinders... Upon the "bt"
>>> command, GDB itself produces more than 157000 frames before hitting
>>> the segfault.
>>
>> Sounds like an infinite recursion (possibly a mutual recursion
>> involving gdb repeatedly injecting new frames into the inferior cc1, or
>> could just be an infinite recursion in the inferior).
>
> It was an infinite recursion, all inside gdb.
>
>>> Have you seen anything like that before?  It would be nice to
>>> understand the root cause of this bug.  I am going to spend some more
>>> time on it, but I've no prior experience in debugging gdb internals.
>>> 
>>> As a workaround, I'd propose perhaps removing the kludge, but the
>>> output looks nice, while the alternative implementation (after
>>> return) is not as informative.
>>
>> Yeah, the rtx-printing is a kludge.
>>
>> The gdbhooks.py code isn't well tested.  I wonder if what you're seeing
>> is a regression, or you're simply uncovering an existing bug.
>
> Talking to Alex made me realize that pretty printing function arguments
> in a backtrace is fundamentally problematic.  Consider a function that
> is passed a pointer whose pointed-to value gets clobbered in a callee of
> that function.  The pretty-printer would access garbage through that
> pointer and that would lead to incorrect results at best and to screwing
> up the whole process at worst (I think, this is the root cause of the
> bug I described).
>
> GDB seems to have some provision for that:
>
>     Function: pretty_printer.to_string (self)
>     [...]
>     Also, depending on the print settings (see Print Settings), the CLI
>     may print just the result of to_string in a stack trace, omitting
>     the result of children.
>
> And in 'Print Settings' I learned that there's the `set print
> frame-arguments all|scalars|none` command.  The default setting is
> "scalars", and that makes sense in our situation, but the deal is
> pointers - 'rtx_def *' in particular - are (rightfully) considered
> scalars.
>
> I tried moving the call to print_inline_rtx from RtxPrinter.to_string()
> to RtxPrinter.children(), but whenever the former is called, the latter
> gets called, too (regardless of display_hint).
>
> So I think, the right direction forward here is to always handle the
> pointed-to types in pretty printers and only do simple forwarding to
> them for pointers.  That way we stay aligned with GDB's printing only
> scalar types in frame infos and keep backtraces safe (at the cost of
> perhaps making them less informative).
>
> Hope I make sense.
>
> Anyway, I wrote up a patch that does that.  Do you like this approach?
>
> The patch is against trunk, but it requires the
> -        type_ = gdbval.type.unqualified()
> +        type_ = gdbval.type.unqualified().strip_typedefs()
> change to reliably show visible effect.
>
> diff --git a/gcc/gdbhooks.py b/gcc/gdbhooks.py
> index a7e665cadb9..15f9738aeee 100644
> --- a/gcc/gdbhooks.py
> +++ b/gcc/gdbhooks.py
> @@ -411,8 +411,8 @@ class RtxPrinter:
>          string for gdb
>          """
>          # We use print_inline_rtx to avoid a trailing newline
> -        gdb.execute('call print_inline_rtx (stderr, (const_rtx) %s, 0)'
> -                    % intptr(self.gdbval))
> +        my_debug_rtx = 
> gdb.lookup_global_symbol('my_debug_inline_rtx').value()
> +        my_debug_rtx(self.gdbval)
>          return ''
>  
>          # or by hand; based on gcc/print-rtl.c:print_rtx
> @@ -428,6 +428,27 @@ class RtxPrinter:
>  
>  ######################################################################
>  
> +class PtrPrinter:
> +    def __init__(self, gdbval):
> +        self.gdbval = gdbval
> +
> +    def to_string (self):
> +        """
> +        Print the pointer value.  We forward to the pretty-printer for
> +        the pointed-to value in children().
> +        """
> +        return '0x%x' % intptr(self.gdbval)
> +
> +    def display_hint (self):
> +        # The choice of displayhint is based purely on aesthetics (it is not
> +        # ideal, but the options are limited).
> +        return 'array'
> +
> +    def children (self):
> +        yield ('pointed-to', self.gdbval.dereference())
> +
> +######################################################################
> +
>  class PassPrinter:
>      def __init__(self, gdbval):
>          self.gdbval = gdbval
> @@ -590,7 +611,8 @@ def build_pretty_printer():
>      pp.add_printer_for_types(['edge_def *'],
>                               'edge',
>                               CfgEdgePrinter)
> -    pp.add_printer_for_types(['rtx_def *'], 'rtx_def', RtxPrinter)
> +    pp.add_printer_for_types(['rtx_def *'], 'rtx_def-forwarder', PtrPrinter)
> +    pp.add_printer_for_types(['rtx_def'], 'rtx_def', RtxPrinter)
>      pp.add_printer_for_types(['opt_pass *'], 'opt_pass', PassPrinter)
>  
>      pp.add_printer_for_regex(r'vec<.*> \*',
> diff --git a/gcc/print-rtl.c b/gcc/print-rtl.c
> index fbb108568b3..2783e921a75 100644
> --- a/gcc/print-rtl.c
> +++ b/gcc/print-rtl.c
> @@ -1023,6 +1023,15 @@ debug (const rtx_def &ref)
>    debug_rtx (&ref);
>  }
>  
> +/* Copy of the above, inlined and w/o a newline, under a different name.  */
> +
> +DEBUG_FUNCTION void
> +my_debug_inline_rtx (const rtx_def &ref)
> +{
> +  rtx_writer w (stderr, 0, false, false, NULL);
> +  w.print_rtx (&ref);
> +}
> +
>  DEBUG_FUNCTION void
>  debug (const rtx_def *ptr)
>  {
>
>
> We can also get 'const rtx_def *' to be pretty printed with e.g.
>
> diff --git a/gcc/gdbhooks.py b/gcc/gdbhooks.py
> index 4f0f9688b35..98c6e13197a 100644
> --- a/gcc/gdbhooks.py
> +++ b/gcc/gdbhooks.py
> @@ -600,7 +626,7 @@ def build_pretty_printer():
>      pp.add_printer_for_types(['edge', 'edge_def *'],
>                               'edge',
>                               CfgEdgePrinter)
> -    pp.add_printer_for_regex(r'.* rtx_def *', 'rtx_def-forwarder', 
> PtrPrinter)
> +    pp.add_printer_for_regex(r'.*rtx_def \*', 'rtx_def-forwarder', 
> PtrPrinter)
>      pp.add_printer_for_types(['rtx_def'], 'rtx_def', RtxPrinter)
>      pp.add_printer_for_types(['opt_pass *'], 'opt_pass', PassPrinter)
>
> Here's a debugging session and output I got with the patch.
>
> $ gdb -ex "b reg_nonzero_bits_for_combine"  \
>    -ex "r" \
>    -ex "f 4" \
>    -ex "p x" \
>    --args ./cc1 -O /mnt/co/gcc/gcc/testsuite/gcc.dg/Wunused-var-3.c
>
> Breakpoint 5, reg_nonzero_bits_for_combine (x=0x7ffff78cae70 = {...}, 
> xmode=DImode, mode=DImode, nonzero=0x7fffffffdcf0) at 
> /mnt/co/gcc/gcc/combine.c:10271
> 10271   {
> #4  set_nonzero_bits_and_sign_copies (x=0x7ffff78d2018 = {...}, 
> set=<optimized out>, data=<optimized out>) at /mnt/co/gcc/gcc/combine.c:1743
> 1743    set_nonzero_bits_and_sign_copies (rtx x, const_rtx set, void *data)
> $1 = 0x7ffff78d2018 = {(reg:DI 86)}

Hi David,

I'd like to ping the patch in the previous message of this thread
(https://gcc.gnu.org/ml/gcc-patches/2019-07/msg00188.html).

The issue it solves (infinite recursion and crash in gdb upon "bt")
blocks the original 1/2 patch.  And the 2/2 (vec support) - which you
also reviewed <https://gcc.gnu.org/ml/gcc-patches/2019-07/msg00063.html>
(thank you), but I haven't yet updated - depends on that.

-- 
Vlad

Reply via email to