Skip to content

Commit

Permalink
Rewrite gdb pretty-printer registration
Browse files Browse the repository at this point in the history
Currently, the Rust pretty-printers are registered in gdb using the
uninformative name "lookup":

    (gdb) info pretty-printer
    global pretty-printers:
    [...]
    objfile /home/tromey/[...]
      lookup

It's nicer for users if the top-level registration is given a clear
name.  Additionally, gdb lets users individually enable and disable
specific printers, provided they are registered correctly.

This patch implements both these ideas.  Now the output looks like:

    (gdb) info pretty-printer
    global pretty-printers:
    [...]
    objfile /home/tromey/[...]
      rust
	StdArc
	StdBTreeMap
	StdBTreeSet
	StdCell
	StdHashMap
	StdHashSet
	StdNonZeroNumber
	StdOsString
	StdRc
	StdRef
	StdRefCell
	StdRefMut
	StdSlice
	StdStr
	StdString
	StdVec
	StdVecDeque
  • Loading branch information
tromey committed Oct 20, 2023
1 parent e76cb8c commit e98beb5
Showing 1 changed file with 78 additions and 55 deletions.
133 changes: 78 additions & 55 deletions src/etc/gdb_lookup.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import gdb
import gdb.printing
import re

from gdb_providers import *
Expand All @@ -9,7 +10,7 @@
gdb_version = [int(num) for num in _gdb_version_matched.groups()] if _gdb_version_matched else []

def register_printers(objfile):
objfile.pretty_printers.append(lookup)
objfile.pretty_printers.append(printer)


# BACKCOMPAT: rust 1.35
Expand Down Expand Up @@ -38,58 +39,80 @@ def check_enum_discriminant(valobj):
return True


def lookup(valobj):
rust_type = classify_rust_type(valobj.type)

if rust_type == RustType.ENUM:
# use enum provider only for GDB <7.12
if gdb_version[0] < 7 or (gdb_version[0] == 7 and gdb_version[1] < 12):
if check_enum_discriminant(valobj):
return EnumProvider(valobj)

if rust_type == RustType.STD_STRING:
return StdStringProvider(valobj)
if rust_type == RustType.STD_OS_STRING:
return StdOsStringProvider(valobj)
if rust_type == RustType.STD_STR:
return StdStrProvider(valobj)
if rust_type == RustType.STD_SLICE:
return StdSliceProvider(valobj)
if rust_type == RustType.STD_VEC:
return StdVecProvider(valobj)
if rust_type == RustType.STD_VEC_DEQUE:
return StdVecDequeProvider(valobj)
if rust_type == RustType.STD_BTREE_SET:
return StdBTreeSetProvider(valobj)
if rust_type == RustType.STD_BTREE_MAP:
return StdBTreeMapProvider(valobj)
if rust_type == RustType.STD_HASH_MAP:
if is_hashbrown_hashmap(valobj):
return StdHashMapProvider(valobj)
else:
return StdOldHashMapProvider(valobj)
if rust_type == RustType.STD_HASH_SET:
hash_map = valobj[valobj.type.fields()[0]]
if is_hashbrown_hashmap(hash_map):
return StdHashMapProvider(valobj, show_values=False)
else:
return StdOldHashMapProvider(hash_map, show_values=False)

if rust_type == RustType.STD_RC:
return StdRcProvider(valobj)
if rust_type == RustType.STD_ARC:
return StdRcProvider(valobj, is_atomic=True)

if rust_type == RustType.STD_CELL:
return StdCellProvider(valobj)
if rust_type == RustType.STD_REF:
return StdRefProvider(valobj)
if rust_type == RustType.STD_REF_MUT:
return StdRefProvider(valobj)
if rust_type == RustType.STD_REF_CELL:
return StdRefCellProvider(valobj)

if rust_type == RustType.STD_NONZERO_NUMBER:
return StdNonZeroNumberProvider(valobj)

# Helper for enum printing that checks the discriminant. Only used in
# older gdb.
def enum_provider(valobj):
if check_enum_discriminant(valobj):
return EnumProvider(valobj)
return None


# Helper to handle both old and new hash maps.
def hashmap_provider(valobj):
if is_hashbrown_hashmap(valobj):
return StdHashMapProvider(valobj)
else:
return StdOldHashMapProvider(valobj)


# Helper to handle both old and new hash sets.
def hashset_provider(valobj):
hash_map = valobj[valobj.type.fields()[0]]
if is_hashbrown_hashmap(hash_map):
return StdHashMapProvider(valobj, show_values=False)
else:
return StdOldHashMapProvider(hash_map, show_values=False)


class PrintByRustType(gdb.printing.SubPrettyPrinter):
def __init__(self, name, provider):
super(PrintByRustType, self).__init__(name)
self.provider = provider

def __call__(self, val):
if self.enabled:
return self.provider(val)
return None


class RustPrettyPrinter(gdb.printing.PrettyPrinter):
def __init__(self, name):
super(RustPrettyPrinter, self).__init__(name, [])
self.type_map = {}

def add(self, rust_type, provider):
# Just use the rust_type as the name.
printer = PrintByRustType(rust_type, provider)
self.type_map[rust_type] = printer
self.subprinters.append(printer)

def __call__(self, valobj):
rust_type = classify_rust_type(valobj.type)
if rust_type in self.type_map:
return self.type_map[rust_type](valobj)
return None


printer = RustPrettyPrinter("rust")
# use enum provider only for GDB <7.12
if gdb_version[0] < 7 or (gdb_version[0] == 7 and gdb_version[1] < 12):
printer.add(RustType.ENUM, enum_provider)
printer.add(RustType.STD_STRING, StdStringProvider)
printer.add(RustType.STD_OS_STRING, StdOsStringProvider)
printer.add(RustType.STD_STR, StdStrProvider)
printer.add(RustType.STD_SLICE, StdSliceProvider)
printer.add(RustType.STD_VEC, StdVecProvider)
printer.add(RustType.STD_VEC_DEQUE, StdVecDequeProvider)
printer.add(RustType.STD_BTREE_SET, StdBTreeSetProvider)
printer.add(RustType.STD_BTREE_MAP, StdBTreeMapProvider)
printer.add(RustType.STD_HASH_MAP, hashmap_provider)
printer.add(RustType.STD_HASH_SET, hashset_provider)
printer.add(RustType.STD_RC, StdRcProvider)
printer.add(RustType.STD_ARC, lambda valobj: StdRcProvider(valobj, is_atomic=True))

printer.add(RustType.STD_CELL, StdCellProvider)
printer.add(RustType.STD_REF, StdRefProvider)
printer.add(RustType.STD_REF_MUT, StdRefProvider)
printer.add(RustType.STD_REF_CELL, StdRefCellProvider)

printer.add(RustType.STD_NONZERO_NUMBER, StdNonZeroNumberProvider)

0 comments on commit e98beb5

Please sign in to comment.