""" /* ScummVM - Graphic Adventure Engine * * ScummVM is the legal property of its developers, whose names * are too numerous to list here. Please refer to the COPYRIGHT * file distributed with this source distribution. * * 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 . * */ """ """ USAGE: inside gdb, use: > source devtools/gdb_pretty_printers.py """ class StringPrinter: "Prints Common::String and Common::U32String" def __init__(self, val): self.val = val def to_string(self): return self.val["_str"].string() def display_hint(self): return "string" class ArrayPrinter: "Prints Common::Array" class _iterator: def __init__(self, start, item_count): self.current_item = start self.item_count = item_count self.current_item_count = 0 self.item_size = 8 * start.dereference().type.sizeof def __iter__(self): return self def __next__(self): if self.current_item_count == self.item_count: raise StopIteration value = self.current_item.dereference() index = self.current_item_count self.current_item_count += 1 self.current_item += 1 return f"[{index}]", value def __init__(self, val): self.val = val def to_string(self): size = self.val["_size"] capacity = self.val["_capacity"] return f"{self.val.type.name} of length {size}, capacity {capacity}" def children(self): return self._iterator(self.val["_storage"], self.val["_size"]) def display_hint(self): return "array" class RBTreeIterator: "Utility iterator for Common::RBTree" def __init__(self, leftmost, item_count): self.current_node = leftmost self.item_count = item_count self.current_item_count = 0 def __iter__(self): return self def __next__(self): if self.current_item_count == self.item_count: raise StopIteration value = self.current_node.dereference()["value"] self.current_item_count += 1 if self.current_node.dereference()["right"]: while self.current_node.dereference()["left"]: self.current_node = self.current_node.dereference()["left"] else: parent = self.current_node.dereference()["parent"] while parent and parent.dereference()["right"] == self.current_node.dereference()["right"]: self.current_node = parent parent = self.current_node.dereference()["parent"] return value class RBTreeMapPrinter: "Prints Common::StableMap and Common::MultiMap" class _iterator: def __init__(self, rb_tree): self.iter = RBTreeIterator(rb_tree["_leftmost"], rb_tree["_size"]) self.count = 0 def __iter__(self): return self def __next__(self): if self.count % 2 == 0: value = next(self.iter) self.current_pair = value item = value["first"] else: item = self.current_pair["second"] self.count += 1 return f"{self.count}", item def __init__(self, val): self.val = val def to_string(self): size = self.val["_items"]["_size"] return f"{self.val.type.name} of length {size}" def children(self): return self._iterator(self.val["_items"]) def display_hint(self): return "map" class ListPrinter: "Prints Common::List" class _iterator: def __init__(self, anchor, typename): self.anchor = anchor self.current_node = anchor["_next"].dereference() self.current_item_count = 0 self.node_type = gdb.lookup_type(f"{typename}::Node") def __iter__(self): return self def __next__(self): if self.current_node.address == self.anchor.address: raise StopIteration value = self.current_node.cast(self.node_type)["_data"] index = self.current_item_count self.current_item_count += 1 self.current_node = self.current_node["_next"].dereference() return f"[{index}]", value def __init__(self, val): self.val = val def to_string(self): if self.val["_anchor"]["_next"] == self.val["_anchor"].address: return f"empty {self.val.type.name}" return self.val.type.name def children(self): return self._iterator(self.val["_anchor"], self.val.type.name) def display_hint(self): return "array" import gdb.printing def build_pretty_printer(): pp = gdb.printing.RegexpCollectionPrettyPrinter( "Common") pp.add_printer('String', '^Common::String$', StringPrinter) pp.add_printer('U32String', '^Common::U32String$', StringPrinter) pp.add_printer('Array', '^Common::Array<.*>$', ArrayPrinter) pp.add_printer('StableMap', '^Common::StableMap<.*>$', RBTreeMapPrinter) pp.add_printer('MultiMap', '^Common::MultiMap<.*>$', RBTreeMapPrinter) pp.add_printer('List', '^Common::List<.*>$', ListPrinter) return pp gdb.printing.register_pretty_printer( gdb.current_objfile(), build_pretty_printer() )