blob: c7de68adb4c7a75ca7852d6a95cbf1ba8bc13619 [file] [log] [blame]
# Type utilities.
# Copyright (C) 2010-2021 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
# 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 <>.
"""Utilities for working with gdb.Types."""
import gdb
def get_basic_type(type_):
"""Return the "basic" type of a type.
type_: The type to reduce to its basic type.
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_RVALUE_REF
or type_.code == gdb.TYPE_CODE_TYPEDEF
if type_.code == gdb.TYPE_CODE_REF or type_.code == gdb.TYPE_CODE_RVALUE_REF:
type_ =
type_ = type_.strip_typedefs()
return type_.unqualified()
def has_field(type_, field):
"""Return True if a type has the specified field.
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.
True if the field is present either in type_ or any baseclass.
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
# NOTE: could be None
if == field:
return True
return False
def make_enum_dict(enum_type):
"""Return a dictionary from a program's enum type.
enum_type: The enum to compute the dictionary for.
The dictionary of the enum.
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.enumval
return enum_dict
def deep_items(type_):
"""Return an iterator that recursively traverses anonymous fields.
type_: The type to traverse. It should be one of
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
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
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): = 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:
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)