Visitar URL original
Syntax error, script doesn't work · Issue #5 · daskol/gdb-colour-filter · GitHub
Skip to content

Syntax error, script doesn't work #5

Closed

Description

@allopislozano

When I include the file in .gdbinit I get the following message:

File "/home/allopis/.gdb/gdb-colour-filter/colour_filter.py", line 21
    def __init__(self, *args, depth=0, **kwargs):
                                  ^
SyntaxError: invalid syntax

Regards!

Activity

  1. allopislozano commented on May 14, 2019

    @allopislozano
    Author

    Looks like *args must be after depth parameter. After fixing that, I get a new error:

      File "/home/allopis/.gdb/gdb-colour-filter/colour_filter.py", line 158
        def __init__(self, frames: Iterator[Frame]):
    
    

    Does this script require python3? my system uses python2 by default. If that's the issue, how can I tell gdb which python interpreter to use?

  2. self-assigned this
    on May 15, 2019
  3. daskol commented on May 15, 2019

    @daskol
    Owner

    Yes, the script requires python 3.5+. It has internally used type hinting. The main reason why I prefer to use the latest python is that python 2 is deprecated and will not be supported since 2020. I highly recommend you to migrate from python 2 to 3.

    Unfortunately, python embedded to gdb as a shared library (check with ldd /usr/bin/gdb). It means that you could not change version of interpreter without recompilation of gdb. Try to apply the patch below. It should solve your issue.

    diff --git a/colour_filter.py b/colour_filter.py
    index 3de0a5b..fbd7deb 100644
    --- a/colour_filter.py
    +++ b/colour_filter.py
    @@ -2,10 +2,8 @@
     #   encoding: utf8
     #   file: colour_filter.py
     
    -from typing import Iterator, Text
    -
     from gdb import parameter as get_parameter
    -from gdb import Frame, frame_filters, execute
    +from gdb import frame_filters, execute
     from gdb.FrameDecorator import FrameDecorator
     
     
    @@ -18,10 +16,10 @@ class FrameColorizer(FrameDecorator):
         Notes: There is not special support Frame.elided() property.
         """
     
    -    def __init__(self, *args, depth=0, **kwargs):
    +    def __init__(self, *args, **kwargs):
             super(FrameColorizer, self).__init__(*args, **kwargs)
     
    -        self._depth = depth
    +        self._depth = kwargs.get(depth, 0)
             self.frame = super(FrameColorizer, self).inferior_frame()
     
         def __str__(self):
    @@ -93,7 +91,7 @@ class FrameColorizer(FrameDecorator):
                 # Here we have something like
                 # > raise + 272 in section .text of /usr/lib/libc.so.6
                 # XXX: gdb.find_pc_line
    -            symbol = gdb.execute('info symbol 0x%016x' % func, False, True)
    +            symbol = execute('info symbol 0x%016x' % func, False, True)
     
                 # But here we truncate layout in binary
                 # > raise + 272
    @@ -154,7 +152,7 @@ class FilterProxy:
         properly on the first and the sole call.
         """
     
    -    def __init__(self, frames: Iterator[Frame]):
    +    def __init__(self, frames):
             self.frames = (FrameColorizer(frame, depth=ix)
                            for ix, frame in enumerate(frames))
     
    @@ -189,7 +187,7 @@ class ColourFilter:
             # dictionary.
             frame_filters[self.name] = self
     
    -    def filter(self, iters: Iterator[Frame]) -> Iterator[Frame]:
    +    def filter(self, iters):
             return FilterProxy(iters)
     
     
  4. allopislozano commented on May 31, 2019

    @allopislozano
    Author

    After applying the patch, it looks like some color is there... for example $gdb prompt is shown in red, but when I try to show a backtrace I get this:
    Python Exception <type 'exceptions.TypeError'> instance has no next() method:
    And I cannot see the frames unfortunately :/

  5. daskol commented on Oct 21, 2019

    @daskol
    Owner

    Sorry for so long delay. Try to apply the patch below. The reason is that iterator protocol differs between Python 2 and Python 3.

    diff --git a/colour_filter.py b/colour_filter.py
    index 2970f2a..bddf1d0 100644
    --- a/colour_filter.py
    +++ b/colour_filter.py
    @@ -163,6 +163,9 @@ class FilterProxy:
             return self
     
         def __next__(self):
    +        return self.next()
    +
    +    def next(self):
             self.unroll_stack()
             raise StopIteration
     
  6. ryanmiao commented on Jun 17, 2020

    @ryanmiao

    Sorry for so long delay. Try to apply the patch below. The reason is that iterator protocol differs between Python 2 and Python 3.

    diff --git a/colour_filter.py b/colour_filter.py
    index 2970f2a..bddf1d0 100644
    --- a/colour_filter.py
    +++ b/colour_filter.py
    @@ -163,6 +163,9 @@ class FilterProxy:
             return self
     
         def __next__(self):
    +        return self.next()
    +
    +    def next(self):
             self.unroll_stack()
             raise StopIteration
     

    hi Dan, after apply this patch, the bt also got an error:

    Python Exception <type 'exceptions.TypeError'> init() got an unexpected keyword argument 'depth':

  7. daskol commented on Jun 17, 2020

    @daskol
    Owner

    @ryanmiao GDB Python API was changed a bit. So, this patch should be usefull if you have applied the previous two.

    diff --git a/colour_filter.py b/colour_filter.py
    index d5b070d..74f5b92 100644
    --- a/colour_filter.py
    +++ b/colour_filter.py
    @@ -16,10 +16,10 @@ class FrameColorizer(FrameDecorator):
         Notes: There is not special support Frame.elided() property.
         """
     
    -    def __init__(self, *args, **kwargs):
    +    def __init__(self, *args, depth=0, **kwargs):
             super(FrameColorizer, self).__init__(*args, **kwargs)
     
    -        self._depth = kwargs.get(depth, 0)
    +        self._depth = depth
             self.frame = super(FrameColorizer, self).inferior_frame()
     
         def __str__(self):
    

    Also, it would be better to use Python 3 with GDB since Python 2 is deprecated.

  8. maksimovichsam commented on Oct 17, 2022

    @maksimovichsam

    I was facing some issues with Python 2 even after all these patches, but I fixed them and got colored backtrace to work with the file below, for those still facing issues.

    #!/usr/bin/env gdb
    #   encoding: utf8
    #   file: colour_filter.py
    
    from gdb import parameter as get_parameter
    from gdb import frame_filters, execute
    from gdb.FrameDecorator import FrameDecorator
    
    
    class FrameColorizer(FrameDecorator):
        """FrameColorizer repeats all actions to get all common frame attribute and
        then spices a bit output with colours. Format of output string is following.
    
        #<depth> <address> in <function> (<frame_args>) at <filename>[:<line>]
    
        Notes: There is not special support Frame.elided() property.
        """
    
        def __init__(self, frame, depth=0):
            super(FrameColorizer, self).__init__(frame)
    
            self._depth = depth
            self.frame = super(FrameColorizer, self).inferior_frame()
    
        def __str__(self):
            is_print_address = get_parameter('print address')
    
            part1 = self.depth()
            part2 = self.function() + ' \033[1;37m(' + self.frame_args() + ')\033[0m'
            part3 = self.filename() + self.line()
    
            if is_print_address:
                part1 += '  ' + self.address() + ' in '
            else:
                part1 += ' '
    
            parts = part1 + part2 + ' at ' + part3
    
            screen_width = self.get_screen_width()
            if screen_width is not None and len(parts) > screen_width:
                shift_width = int(self.length(part1)) - 1
                shift_width -= 3 * int(is_print_address)  # compensate ' in ' part
                value = part1 + part2 + '\n'
                value += ' ' * shift_width + ' at ' + part3
            else:
                value = parts
    
            return value
    
        def address(self):
            address = super(FrameColorizer, self).address()
            return '\033[1;30m0x%016x\033[0m' % address
    
        def depth(self):
            return '\033[1;37m#%-3d\033[0m' % self._depth
    
        def filename(self):
            filename = super(FrameColorizer, self).filename()
            return '\033[0;36m%s\033[0m' % filename
    
        def frame_args(self):
            try:
                block = self.frame.block()
            except RuntimeError:
                block = None
    
            while block is not None:
                if block.function is not None:
                    break
                block = block.superblock
    
            if block is None:
                return ''
    
            args = []
    
            for sym in block:
                if not sym.is_argument:
                    continue;
                val = sym.value(self.frame)
                arg = '%s=%s' % (sym, val) if str(val) else str(sym)
                args.append(arg)
    
            return ', '.join(args)
    
        def function(self):
            func = super(FrameColorizer, self).function()
    
            # GDB could somehow resolve function name by its address.
            # See details here https://cygwin.com/ml/gdb/2017-12/msg00013.html
            if isinstance(func, int):
                # Here we have something like
                # > raise + 272 in section .text of /usr/lib/libc.so.6
                # XXX: gdb.find_pc_line
                symbol = execute('info symbol 0x%016x' % func, False, True)
    
                # But here we truncate layout in binary
                # > raise + 272
                name = symbol[:symbol.find('in section')].strip()
    
                # Check if we in format
                # > smthing + offset
                parts = name.rsplit(' ', 1)
                # > raise
                if len(parts) == 1:
                    return name
    
                try:
                    offset = hex(int(parts[1]))
                except ValueError:
                    return name
    
                return '\033[1;34m' + parts[0] + ' ' + offset + '\033[0m'
            else:
                return '\033[1;34m' + str(func) + '\033[0m'
    
        def get_screen_width(self):
            """Get screen width from GDB. Source format is following
            """
            return get_parameter('width')
    
        def line(self):
            value = super(FrameColorizer, self).line()
            return '\033[0;35m:%d\033[0m' % value if value else ''
    
        @staticmethod
        def length(colored_string):
            """This function calculates length of string with terminal control
            sequences.
            """
            start = 0
            term_seq_len = 0
    
            while True:
                begin = colored_string.find('\033', start)
    
                if begin == -1:
                    break
    
                end = colored_string.find('m', begin)
    
                if end == -1:
                    end = len(s)
    
                term_seq_len += end - begin + 1
                start = end
    
            return len(colored_string) - term_seq_len
    
    
    class FilterProxy:
        """FilterProxy class keep ensures that frame iterator will be comsumed
        properly on the first and the sole call.
        """
    
        def __init__(self, frames):
            self.frames = (FrameColorizer(frame, ix)
                           for ix, frame in enumerate(frames))
    
        def __iter__(self):
            return self
    
        def next(self):
            self.unroll_stack()
            raise StopIteration
    
        def unroll_stack(self):
            output = (str(frame) for frame in self.frames)
            print('\n'.join(output))
    
    
    class ColourFilter:
    
        def __init__(self, name='backtrace-filter', priority=0, enabled=True):
            """Frame filter with the lower priority that consumes every frame and
            colouring output.
    
            :param name: The name of the filter that GDB will display.
            :param priority: The priority of the filter relative to other filters.
            :param enabled: A boolean that indicates whether this filter is enabled
            and should be executed.
            """
            self.name = name
            self.priority = priority
            self.enabled = enabled
    
            # Register this frame filter with the global frame_filters
            # dictionary.
            frame_filters[self.name] = self
    
        def filter(self, iters):
            return FilterProxy(iters)
    
    
    ColourFilter()  # register colour filter forcibly
    
  9. daskol commented on Oct 18, 2022

    @daskol
    Owner

    @maksimovichsam Nice! However, I still recommend to switch to Python 3 or newer version of GDB with built-in colour support.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

No labels
No labels

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions