# Type utilities.
|
# Copyright (C) 2010-2017 Free Software Foundation, Inc.
|
|
# This program is free software; you can redistribute it and/or modify
|
# it under the terms of the GNU General Public License as published by
|
# the Free Software Foundation; either version 3 of the License, or
|
# (at your option) any later version.
|
#
|
# This program is distributed in the hope that it will be useful,
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
# GNU General Public License for more details.
|
#
|
# You should have received a copy of the GNU General Public License
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
"""Utilities for working with gdb.Types."""
|
|
import gdb
|
|
|
def get_basic_type(type_):
|
"""Return the "basic" type of a type.
|
|
Arguments:
|
type_: The type to reduce to its basic type.
|
|
Returns:
|
type_ with const/volatile is stripped away,
|
and typedefs/references converted to the underlying type.
|
"""
|
|
while (type_.code == gdb.TYPE_CODE_REF or
|
type_.code == gdb.TYPE_CODE_TYPEDEF):
|
if type_.code == gdb.TYPE_CODE_REF:
|
type_ = type_.target()
|
else:
|
type_ = type_.strip_typedefs()
|
return type_.unqualified()
|
|
|
def has_field(type_, field):
|
"""Return True if a type has the specified field.
|
|
Arguments:
|
type_: The type to examine.
|
It must be one of gdb.TYPE_CODE_STRUCT, gdb.TYPE_CODE_UNION.
|
field: The name of the field to look up.
|
|
Returns:
|
True if the field is present either in type_ or any baseclass.
|
|
Raises:
|
TypeError: The type is not a struct or union.
|
"""
|
|
type_ = get_basic_type(type_)
|
if (type_.code != gdb.TYPE_CODE_STRUCT and
|
type_.code != gdb.TYPE_CODE_UNION):
|
raise TypeError("not a struct or union")
|
for f in type_.fields():
|
if f.is_base_class:
|
if has_field(f.type, field):
|
return True
|
else:
|
# NOTE: f.name could be None
|
if f.name == field:
|
return True
|
return False
|
|
|
def make_enum_dict(enum_type):
|
"""Return a dictionary from a program's enum type.
|
|
Arguments:
|
enum_type: The enum to compute the dictionary for.
|
|
Returns:
|
The dictionary of the enum.
|
|
Raises:
|
TypeError: The type is not an enum.
|
"""
|
|
if enum_type.code != gdb.TYPE_CODE_ENUM:
|
raise TypeError("not an enum type")
|
enum_dict = {}
|
for field in enum_type.fields():
|
# The enum's value is stored in "enumval".
|
enum_dict[field.name] = field.enumval
|
return enum_dict
|
|
|
def deep_items (type_):
|
"""Return an iterator that recursively traverses anonymous fields.
|
|
Arguments:
|
type_: The type to traverse. It should be one of
|
gdb.TYPE_CODE_STRUCT or gdb.TYPE_CODE_UNION.
|
|
Returns:
|
an iterator similar to gdb.Type.iteritems(), i.e., it returns
|
pairs of key, value, but for any anonymous struct or union
|
field that field is traversed recursively, depth-first.
|
"""
|
for k, v in type_.iteritems ():
|
if k:
|
yield k, v
|
else:
|
for i in deep_items (v.type):
|
yield i
|
|
class TypePrinter(object):
|
"""The base class for type printers.
|
|
Instances of this type can be used to substitute type names during
|
'ptype'.
|
|
A type printer must have at least 'name' and 'enabled' attributes,
|
and supply an 'instantiate' method.
|
|
The 'instantiate' method must either return None, or return an
|
object which has a 'recognize' method. This method must accept a
|
gdb.Type argument and either return None, meaning that the type
|
was not recognized, or a string naming the type.
|
"""
|
|
def __init__(self, name):
|
self.name = name
|
self.enabled = True
|
|
def instantiate(self):
|
return None
|
|
# Helper function for computing the list of type recognizers.
|
def _get_some_type_recognizers(result, plist):
|
for printer in plist:
|
if printer.enabled:
|
inst = printer.instantiate()
|
if inst is not None:
|
result.append(inst)
|
return None
|
|
def get_type_recognizers():
|
"Return a list of the enabled type recognizers for the current context."
|
result = []
|
|
# First try the objfiles.
|
for objfile in gdb.objfiles():
|
_get_some_type_recognizers(result, objfile.type_printers)
|
# Now try the program space.
|
_get_some_type_recognizers(result, gdb.current_progspace().type_printers)
|
# Finally, globals.
|
_get_some_type_recognizers(result, gdb.type_printers)
|
|
return result
|
|
def apply_type_recognizers(recognizers, type_obj):
|
"""Apply the given list of type recognizers to the type TYPE_OBJ.
|
If any recognizer in the list recognizes TYPE_OBJ, returns the name
|
given by the recognizer. Otherwise, this returns None."""
|
for r in recognizers:
|
result = r.recognize(type_obj)
|
if result is not None:
|
return result
|
return None
|
|
def register_type_printer(locus, printer):
|
"""Register a type printer.
|
PRINTER is the type printer instance.
|
LOCUS is either an objfile, a program space, or None, indicating
|
global registration."""
|
|
if locus is None:
|
locus = gdb
|
locus.type_printers.insert(0, printer)
|