Skip to content

Instantly share code, notes, and snippets.

@ZedThree
Created November 29, 2021 11:14
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ZedThree/36a53f3136f43d8170cd6e0c57fc0fe2 to your computer and use it in GitHub Desktop.
Save ZedThree/36a53f3136f43d8170cd6e0c57fc0fe2 to your computer and use it in GitHub Desktop.
GDB pretty-printer for mpark.variant based on the libstdc++ pretty-printers
# Pretty-printers for mpark.variant based on those for libstdc++.
# Copyright (C) 2008-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
# 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/>.
import gdb
import re
# Python 3 stuff
Iterator = object
# Python 3 folds these into the normal functions.
imap = map
izip = zip
# Also, int subsumes long
long = int
# Try to use the new-style pretty-printing if available.
_use_gdb_pp = True
try:
import gdb.printing
except ImportError:
_use_gdb_pp = False
# Try to install type-printers.
_use_type_printing = False
try:
import gdb.types
if hasattr(gdb.types, "TypePrinter"):
_use_type_printing = True
except ImportError:
pass
def get_template_arg_list(type_obj):
"Return a type's template arguments as a list"
n = 0
template_args = []
while True:
try:
template_args.append(type_obj.template_argument(n))
except RuntimeError:
return template_args
n += 1
class SingleObjContainerPrinter(object):
"Base class for printers of containers of single objects"
def __init__(self, val, viz, hint=None):
self.contained_value = val
self.visualizer = viz
self.hint = hint
def _recognize(self, type):
"""Return TYPE as a string after applying type printers"""
global _use_type_printing
if not _use_type_printing:
return str(type)
return gdb.types.apply_type_recognizers(
gdb.types.get_type_recognizers(), type
) or str(type)
class _contained(Iterator):
def __init__(self, val):
self.val = val
def __iter__(self):
return self
def __next__(self):
if self.val is None:
raise StopIteration
retval = self.val
self.val = None
return ("[contained value]", retval)
def children(self):
if self.contained_value is None:
return self._contained(None)
if hasattr(self.visualizer, "children"):
return self.visualizer.children()
return self._contained(self.contained_value)
def display_hint(self):
# if contained value is a map we want to display in the same way
if hasattr(self.visualizer, "children") and hasattr(
self.visualizer, "display_hint"
):
return self.visualizer.display_hint()
return self.hint
class MparkVariantPrinter(SingleObjContainerPrinter):
"Print a mpark::variant"
def __init__(self, typename, val):
alternatives = get_template_arg_list(val.type)
self.typename = (
f"{typename}<{', '.join([self._recognize(alt) for alt in alternatives]),}>"
)
self.index = val["impl_"]["index_"]
if self.index >= len(alternatives):
self.contained_type = None
contained_value = None
visualizer = None
else:
self.contained_type = alternatives[int(self.index)]
addr = val["impl_"]["data_"].address
contained_value = addr.cast(self.contained_type.pointer()).dereference()
visualizer = gdb.default_visualizer(contained_value)
super().__init__(contained_value, visualizer, "array")
def to_string(self):
if self.contained_value is None:
return f"{self.typename} [no contained value]"
if hasattr(self.visualizer, "children"):
return f"{self.typename} [index {self.index}] containing {self.visualizer.to_string}"
return f"{self.typename} [index {self.index}]"
# A "regular expression" printer which conforms to the
# "SubPrettyPrinter" protocol from gdb.printing.
class RxPrinter(object):
def __init__(self, name, function):
super(RxPrinter, self).__init__()
self.name = name
self.function = function
self.enabled = True
def invoke(self, value):
if not self.enabled:
return None
if value.type.code == gdb.TYPE_CODE_REF:
if hasattr(gdb.Value, "referenced_value"):
value = value.referenced_value()
return self.function(self.name, value)
# A pretty-printer that conforms to the "PrettyPrinter" protocol from
# gdb.printing. It can also be used directly as an old-style printer.
class Printer(object):
def __init__(self, name):
super(Printer, self).__init__()
self.name = name
self.subprinters = []
self.lookup = {}
self.enabled = True
self.compiled_rx = re.compile("^([a-zA-Z0-9_:]+)(<.*>)?$")
def add(self, name, function):
printer = RxPrinter(name, function)
self.subprinters.append(printer)
self.lookup[name] = printer
@staticmethod
def get_basic_type(type):
# If it points to a reference, get the reference.
if type.code == gdb.TYPE_CODE_REF:
type = type.target()
# Get the unqualified type, stripped of typedefs.
type = type.unqualified().strip_typedefs()
return type.tag
def __call__(self, val):
typename = self.get_basic_type(val.type)
if not typename:
return None
# All the types we match are template types, so we can use a
# dictionary.
match = self.compiled_rx.match(typename)
if not match:
return None
basename = match.group(1)
if val.type.code == gdb.TYPE_CODE_REF:
if hasattr(gdb.Value, "referenced_value"):
val = val.referenced_value()
if basename in self.lookup:
return self.lookup[basename].invoke(val)
# Cannot find a pretty printer. Return None.
return None
mpark_variant_printer = None
def register_mpark_variant_printers(obj):
"Register libstdc++ pretty-printers with objfile Obj."
global _use_gdb_pp
global mpark_variant_printer
if _use_gdb_pp:
gdb.printing.register_pretty_printer(obj, mpark_variant_printer)
else:
if obj is None:
obj = gdb
obj.pretty_printers.append(mpark_variant_printer)
def build_mpark_variant_dictionary():
global mpark_variant_printer
mpark_variant_printer = Printer("mpark")
mpark_variant_printer.add("mpark::variant", MparkVariantPrinter)
build_mpark_variant_dictionary()
register_mpark_variant_printers(None)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment