summaryrefslogblamecommitdiffstats
path: root/make-gdb.py
blob: ba3987da2e7cef9a08e3bffd980ebcaaac17de5f (plain) (tree)
1
2
3
4
5
6
7
8
9
10
                                             


                                                   
 


                               

 
                   
                                              











                                            







                                                            





                                                        




















                                                                          
 
























                                                                          
             


                                                             
                  


                                                             
 

              


                           
                                

                            
                                           


                        

                                                 
                                                                          



























                                                                          

                              
                                  

                            
                                              


                        
                                                             



















                                                                     
 
                               
                                    



                            
                                               


                        
                                                





                                                                               
                                      





                                      
                                                


                                                                                            
                                               
                      
                                                             


                            
                                                           

                    
 
                                 
                               

                            
                                                   


                                                 
                                               


                                   
                                                   






                                                     
                                                           

                    
 
                                     
                                    



                            
                                                        


                        
                                                    


                                    
                                                   

                                                                                                   

                                                                 

                              
                                 

                                  
                                                                        






                                                         
                                                           

                    
 
                           
                                          

                                                              
                                                                    





                                                                                     
 


                                                                          
"""GDB pretty-printer macros for GNU Make."""

import gdb  # pylint: disable=import-error
import gdb.printing  # pylint: disable=import-error


# Memoize types we commonly use
_TYPES = {}


def getType(tname):
    """Given a type name return a GDB type."""
    global _TYPES
    if tname not in _TYPES:
        tn = tname.rstrip('*')
        if tn not in _TYPES:
            _TYPES[tn] = gdb.lookup_type(tn)
        while tn != tname:
            # Want a pointer type
            t = tn
            tn += '*'
            _TYPES[tn] = _TYPES[t].pointer()
    return _TYPES[tname]


def isNullptr(val):
    """Return True if the value is a null pointer."""
    return int(val.cast(getType('unsigned long long'))) == 0


class ShowArgv(gdb.Command):
    """Print a null-terminated array of strings.

    Argument:
        A char** where the last one is NULL (e.g., argv)
    """

    def __init__(self):
        """Create the showargv function."""
        gdb.Command.__init__(self, "showargv", gdb.COMMAND_USER)

    def invoke(self, arg, from_tty):
        """Show the argv."""
        args = gdb.string_to_argv(arg)
        if len(args) != 1:
            raise gdb.GdbError(self._usage)

        val = gdb.parse_and_eval(args[0])
        if val is None:
            raise gdb.GdbError('%s is not a valid expression' % (args[0]))

        strs = []
        while not isNullptr(val.dereference()):
            strs.append('"'+val.dereference().string()+'"')
            val += 1

        gdb.write("[%d] = [%s]\n" % (len(strs), ', '.join(strs)))
        gdb.flush()


ShowArgv()


class ShowNextList(gdb.Command):
    """Print a structure that has a "next" pointer.

    Argument:
        A pointer to a struct which contains a "next" member.
    """

    _usage = 'usage: showlist <listptr>'

    def __init__(self):
        """Create a "showlist" function."""
        gdb.Command.__init__(self, "showlist", gdb.COMMAND_USER)

    def invoke(self, arg, from_tty):
        """Show the elements in the provided list."""
        args = gdb.string_to_argv(arg)
        if len(args) != 1:
            raise gdb.GdbError(self._usage)

        val = gdb.parse_and_eval(args[0])
        if val is None:
            raise gdb.GdbError('%s is not a valid expression' % (args[0]))
        i = 0
        while not isNullptr(val):
            gdb.write("%s : %s\n" % (val, val.dereference()))
            gdb.flush()
            i += 1
            val = val['next']
        gdb.write("%s contains %d elements\n" % (args[0], i))
        gdb.flush()


ShowNextList()


class FileLocation(object):
    """Print a file location."""

    def __init__(self, val):
        """Create a FileLocation object."""
        self.val = val

    def to_string(self):
        """Convert a FileLocation to a string."""
        if int(self.val['filenm']):
            return "%s:%d" % (str(self.val['filenm']), self.val['lineno'])
        return 'NILF'


class StringListPrinter(object):
    """Print a stringlist."""

    def __init__(self, val):
        """Create a StringListPrinter object."""
        self.val = val

    def to_string(self):
        """Convert a HashTable into a string."""
        return "size=%d, capacity=%d" % (self.val['idx'], self.val['max'])

    def children(self):
        """Yield each string in the list."""
        i = 0
        elts = self.val['list']
        while i < self.val['idx']:
            nm = '[%d] ' % i
            yield (nm, elts.dereference())
            i += 1
            elts += 1

    def display_hint(self):
        """Show the display hint for the pretty-printer."""
        return 'array'


class VariablePrinter(object):
    """Print a struct variable."""

    def __init__(self, val):
        """Create a VariablePrinter object."""
        self.val = val

    def to_string(self):
        """Convert a VariablePrinter object into a string."""
        if self.val['append']:
            a = '+='
        elif self.val['conditional']:
            a = '?='
        else:
            a = '='
        flags = []
        s = str(self.val['flavor'])
        if s != 'f_bogus':
            flags.append(s)
        s = str(self.val['origin'])
        if s != 'o_default':
            flags.append(s)
        s = str(self.val['export'])
        if s != 'v_default':
            flags.append(s)
        return '%s[%s]: "%s" %s "%s"' % (
            self.val['fileinfo'], ','.join(flags),
            self.val['name'].string(), a, self.val['value'].string())


class HashTablePrinter(object):
    """Pretty-print a hash table."""

    DELITEM = None

    def __init__(self, val):
        """Create a HashTablePrinter object."""
        self.val = val

    def to_string(self):
        """Convert a HashTable into a string."""
        return "size=%d, capacity=%d, empty=%d, collisions=%d, rehashes=%d" % (
            self.val['ht_size'], self.val['ht_capacity'],
            self.val['ht_empty_slots'], self.val['ht_collisions'],
            self.val['ht_rehashes'])

    def children(self):
        """Yield each ID and value."""
        for (i, v) in self.iterator():
            nm = '[%d] ' % i
            yield (nm, i)
            yield (nm, v)

    def iterator(self):
        """Provide an iterator for HashTable."""
        if HashTablePrinter.DELITEM is None:
            HashTablePrinter.DELITEM = gdb.lookup_global_symbol('hash_deleted_item').value()
        lst = self.val['ht_vec']
        for i in range(0, self.val['ht_size']):
            v = lst[i]
            if int(v) != 0 and v != HashTablePrinter.DELITEM:
                yield (i, v)

    def display_hint(self):
        """Show the display hint for the pretty-printer."""
        return 'map'


class VariableSetPrinter(object):
    """Print a variable_set."""

    def __init__(self, val):
        """Create a variable_set pretty-printer."""
        self.tbl = HashTablePrinter(val['table'])

    def to_string(self):
        """Convert a variable_set to string."""
        return self.tbl.to_string()

    def children(self):
        """Iterate through variables and values."""
        for (i, v) in self.tbl.iterator():
            ptr = v.cast(getType('struct variable*'))
            nm = '[%d] ' % (i)
            yield (nm, ptr)
            yield (nm, str(ptr.dereference()))

    def display_hint(self):
        """Show the display hint for the pretty-printer."""
        return 'map'


class VariableSetListPrinter(object):
    """Print a variable_set_list."""

    GLOBALSET = None

    def __init__(self, val):
        """Create a variable_set_list pretty-printer."""
        self.val = val

    def to_string(self):
        """Convert a variable_set_list to string."""
        return str(self.val.address)

    def children(self):
        """Iterate through variables and values."""
        if VariableSetListPrinter.GLOBALSET is None:
            block = gdb.lookup_global_symbol('init_hash_global_variable_set').symtab.static_block()
            VariableSetListPrinter.GLOBALSET = gdb.lookup_symbol(
                'global_variable_set', block)[0].value().address
        ptr = self.val.address
        i = 0
        while not isNullptr(ptr):
            nm = '[%d] ' % (i)
            yield (nm, ptr['set'])
            if int(ptr['set']) == int(VariableSetListPrinter.GLOBALSET):
                yield (nm, "global_variable_set")
            else:
                yield (nm, str(ptr['set'].dereference()))
            i += 1
            ptr = ptr['next']

    def display_hint(self):
        """Show the display hint for the pretty-printer."""
        return 'map'


def build_pretty_printer():
    """Install all the pretty-printers."""
    pp = gdb.printing.RegexpCollectionPrettyPrinter("gnumake")
    pp.add_printer('floc', r'^floc$', FileLocation)
    pp.add_printer('stringlist', r'^stringlist$', StringListPrinter)
    pp.add_printer('variable', r'^variable$', VariablePrinter)
    pp.add_printer('hashtable', r'^hash_table$', HashTablePrinter)
    pp.add_printer('variableset', r'^variable_set$', VariableSetPrinter)
    pp.add_printer('variablesetlist', r'^variable_set_list$', VariableSetListPrinter)
    return pp


# Use replace=True so we can re-source this file
gdb.printing.register_pretty_printer(gdb.current_objfile(),
                                     build_pretty_printer(), replace=True)