"https://sourceware.org/gdb/current/onlinedocs/gdb.html/Python-API.html#Python-API" import gdb # type: ignore class VectorPrinter(gdb.ValuePrinter): """兼容新旧注册方式的最终方案""" def __init__(self, val: gdb.Value): self.val: gdb.Value = val @staticmethod def check_type(val: gdb.Value) -> bool: """类型检查(兼容匿名结构体)""" try: if val.type.code not in (gdb.TYPE_CODE_STRUCT, gdb.TYPE_CODE_TYPEDEF): return False if val.type.name == "scc_cstring_t": return False fields = val.type.fields() if not fields: return False exp = ["size", "cap", "data"] for t in fields: if t.name in exp: exp.remove(t.name) else: return False return True except gdb.error: return False except ValueError: return False except TypeError: return False except Exception as e: print(f"[DEBUG] Unknown exception type: {type(e).__name__}") print(f"[DEBUG] Exception details: {e}") print( f"[DEBUG] val type: {val.type if hasattr(val, 'type') else 'no type attr'}" ) return False def to_string(self): """ GDB will call this method to display the string representation of the value passed to the object's constructor. This is a basic method, and is optional. When printing from the CLI, if the to_string method exists, then GDB will prepend its result to the values returned by children. Exactly how this formatting is done is dependent on the display hint, and may change as more hints are added. Also, depending on the print settings (see Print Settings), the CLI may print just the result of to_string in a stack trace, omitting the result of children. If this method returns a string, it is printed verbatim. Otherwise, if this method returns an instance of gdb.Value, then GDB prints this value. This may result in a call to another pretty-printer. If instead the method returns a Python value which is convertible to a gdb.Value, then GDB performs the conversion and prints the resulting value. Again, this may result in a call to another pretty-printer. Python scalars (integers, floats, and booleans) and strings are convertible to gdb.Value; other types are not. Finally, if this method returns None then no further operations are performed in this method and nothing is printed. If the result is not one of these types, an exception is raised. https://sourceware.org/gdb/current/onlinedocs/gdb.html/Pretty-Printing-API.html#Pretty-Printing-API """ return ( f"vector({self.val.address} size={self.val['size']}, cap={self.val['cap']})" ) def display_hint(self): """ The CLI may call this method and use its result to change the formatting of a value. The result will also be supplied to an MI consumer as a 'displayhint' attribute of the variable being printed. This is a basic method, and is optional. If it does exist, this method must return a string or the special value None. Some display hints are predefined by GDB: 'array' Indicate that the object being printed is “array-like”. The CLI uses this to respect parameters such as set print elements and set print array. 'map' Indicate that the object being printed is “map-like”, and that the children of this value can be assumed to alternate between keys and values. 'string' Indicate that the object being printed is “string-like”. If the printer's to_string method returns a Python string of some kind, then GDB will call its internal language-specific string-printing function to format the string. For the CLI this means adding quotation marks, possibly escaping some characters, respecting set print elements, and the like. The special value None causes GDB to apply the default display rules. https://sourceware.org/gdb/current/onlinedocs/gdb.html/Pretty-Printing-API.html#Pretty-Printing-API """ return "array" def num_children(self): """ This is not a basic method, so GDB will only ever call it for objects derived from gdb.ValuePrinter. If available, this method should return the number of children. None may be returned if the number can't readily be computed. https://sourceware.org/gdb/current/onlinedocs/gdb.html/Pretty-Printing-API.html#Pretty-Printing-API """ return int(self.val["size"]) def children(self): """ This is not a basic method, so GDB will only ever call it for objects derived from gdb.ValuePrinter. If available, this method should return the child item (that is, a tuple holding the name and value of this child) indicated by n. Indices start at zero. GDB provides a function which can be used to look up the default pretty-printer for a gdb.Value: https://sourceware.org/gdb/current/onlinedocs/gdb.html/Pretty-Printing-API.html#Pretty-Printing-API """ size = int(self.val["size"]) cap = int(self.val["cap"]) data_ptr = self.val["data"] if cap == 0 or data_ptr == 0: return [] # 使用 GDB 内置数组转换 array = data_ptr.dereference() array = array.cast(data_ptr.type.target().array(cap - 1)) for i in range(size): # state = "" if i < size else "" try: value = array[i] yield (f"[{i}] {value.type} {value.address}", value) except gdb.MemoryError: yield (f"[{i}]", "") class HashTablePrinter(gdb.ValuePrinter): def __init__(self, val: gdb.Value): self.val: gdb.Value = val @staticmethod def check_type(val: gdb.Value) -> bool: if val.type.name in ["scc_hashtable_t", "scc_hashtable"]: return True return False def append_printer(): "注册方式一:传统append方法(您之前有效的方式)self" gdb.pretty_printers.append( lambda val: VectorPrinter(val) if VectorPrinter.check_type(val) else None ) def register_new_printer(): "注册方式二:新版注册方法(备用方案)" def str_lookup_function(val): if VectorPrinter.check_type(val) is False: return None ret = VectorPrinter(val) # print( # f"ret {ret}, type {val.type.name}, {[(i.name, i.type) for i in val.type.fields()]}" # ) return ret gdb.printing.register_pretty_printer(gdb.current_objfile(), str_lookup_function) # if gdb.current_progspace() is not None: # pts = gdb.current_progspace().pretty_printers # print(pts, len(pts)) # pts.append(str_lookup_function) class VectorInfoCommand(gdb.Command): """保持原有命令不变""" def __init__(self): super().__init__("vector_info", gdb.COMMAND_USER) def invoke(self, argument, from_tty): val = gdb.parse_and_eval(argument) if not VectorPrinter.check_type(val): print("Invalid vector") return printer = VectorPrinter(val) print("=== Vector Details ===") print("Size:", val["size"]) print("Capacity:", val["cap"]) print("Elements:") for name, value in printer.children(): print(f" {name}: {value}") if __name__ == "__main__": # 双重注册保证兼容性 # append_printer() # 保留您原来有效的方式 register_new_printer() # 添加新版注册 VectorInfoCommand()