From fd4b6828f9ccf86b91b292913a11c23961944c94 Mon Sep 17 00:00:00 2001 From: Michael Alexsander Date: Mon, 6 Apr 2026 17:32:01 -0300 Subject: [PATCH] Fix/improve the pretty print for GDB --- misc/utility/godot_gdb_pretty_print.py | 92 +++++++++++++++++++++----- 1 file changed, 76 insertions(+), 16 deletions(-) diff --git a/misc/utility/godot_gdb_pretty_print.py b/misc/utility/godot_gdb_pretty_print.py index 6b160e4751..13da9eb618 100644 --- a/misc/utility/godot_gdb_pretty_print.py +++ b/misc/utility/godot_gdb_pretty_print.py @@ -34,7 +34,11 @@ class GodotStringNamePrinter: self.value = value def to_string(self): - return self.value["_data"]["name"]["_cowdata"]["_ptr"] + data = self.value["_data"] + if data == 0: + return "" + + return '"%s"' % data["name"]["_cowdata"]["_ptr"].string() # Hint that the object is string-like. def display_hint(self): @@ -47,7 +51,25 @@ class GodotStringPrinter: self.value = value def to_string(self): - return self.value["_cowdata"]["_ptr"] + value = self.value["_cowdata"]["_ptr"] + if int(value) == 0: + return "" + + result = '"' + + i = 0 + while True: + cp = int((value + i).dereference()) + + # End found, we're done. + if cp == 0 or cp > 0x10FFFF: + break + + result += chr(cp) + i += 1 + + result += '"' + return result # Hint that the object is string-like. def display_hint(self): @@ -64,29 +86,33 @@ class GodotVectorPrinter: # The offsets are constants on the C++ side, optimized out, so not accessible to us. # I'll just hard code the observed values and hope they are the same forever. # See core/templates/cowdata.h - SIZE_OFFSET = 8 - DATA_OFFSET = 16 + SIZE_OFFSET = 16 + DATA_OFFSET = 32 # Figures out the number of elements in the vector. def get_size(self): cowdata = self.value["_cowdata"] - if cowdata["_ptr"] == 0: + if not cowdata["_ptr"]: return 0 - else: - # The ptr member of cowdata does not point to the beginning of the - # cowdata. It points to the beginning of the data section of the cowdata. - # To get to the length section, we must back up to the beginning of the struct, - # then move back forward to the size. - # cf. CowData::_get_size - ptr = cowdata["_ptr"].cast(gdb.lookup_type("uint8_t").pointer()) - return int((ptr - self.DATA_OFFSET + self.SIZE_OFFSET).dereference()) + + # The ptr member of cowdata does not point to the beginning of the + # cowdata. It points to the beginning of the data section of the cowdata. + # To get to the length section, we must back up to the beginning of the struct, + # then move back forward to the size. + # cf. CowData::_get_size + ptr = cowdata["_ptr"].cast(gdb.lookup_type("uint8_t").pointer()) + count = int((ptr - self.DATA_OFFSET + self.SIZE_OFFSET).dereference()) + + # Cap it, to avoid infinite loops if uninitialized. + return min(1024, count) # Lists children of the value, in this case the vector's items. def children(self): # Return nothing if ptr is null. ptr = self.value["_cowdata"]["_ptr"] - if ptr == 0: + if int(ptr) == 0: return + # Yield the items one by one. for i in range(self.get_size()): yield str(i), (ptr + i).dereference() @@ -102,14 +128,48 @@ class GodotVectorPrinter: VECTOR_REGEX = re.compile("^Vector<.*$") +# Printer for Godot LocalVector variables. +class GodotLocalVectorPrinter: + def __init__(self, value): + self.value = value + + # Lists children of the value, in this case the vector's items. + def children(self): + # Return nothing if data is null. + data = self.value["data"] + if data == 0: + return + + # Yield the items one by one. Capping it, to avoid infinite loops if uninitialized. + for i in range(min(1024, self.value["count"])): + yield str(i), (data + i).dereference() + + def to_string(self): + return "%s [%d]" % (self.value.type.name, self.value["count"]) + + # Hint that the object is array-like. + def display_hint(self): + return "array" + + +LOCAL_VECTOR_REGEX = re.compile("^LocalVector<.*$") + + # Tries to find a pretty printer for a debugger value. def lookup_pretty_printer(value): if value.type.name == "StringName": return GodotStringNamePrinter(value) + if value.type.name == "String": return GodotStringPrinter(value) - if value.type.name and VECTOR_REGEX.match(value.type.name): - return GodotVectorPrinter(value) + + if value.type.name: + if VECTOR_REGEX.match(value.type.name): + return GodotVectorPrinter(value) + + if LOCAL_VECTOR_REGEX.match(value.type.name): + return GodotLocalVectorPrinter(value) + return None