Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/misc/utility/godot_gdb_pretty_print.py
9896 views
1
"""
2
Load this file to your GDB session to enable pretty-printing of some Godot C++ types.
3
4
GDB command: `source misc/utility/godot_gdb_pretty_print.py`.
5
6
To load these automatically in Visual Studio Code, add the source command to
7
the `setupCommands` of your configuration in `launch.json`:
8
```json
9
"setupCommands": [
10
...
11
{
12
"description": "Load custom pretty-printers for Godot types.",
13
"text": "source ${workspaceFolder}/misc/utility/godot_gdb_pretty_print.py"
14
}
15
]
16
```
17
Other UIs that use GDB under the hood are likely to have their own ways to achieve this.
18
19
To debug this script it's easiest to use the interactive python from a command-line
20
GDB session. Stop at a breakpoint, then use python-interactive to enter the python shell
21
and acquire a `Value` object using `gdb.selected_frame().read_var("variable name")`.
22
From there you can figure out how to print it nicely.
23
"""
24
25
import re
26
27
import gdb # type: ignore
28
import gdb.printing # type: ignore
29
30
31
# Printer for Godot StringName variables.
32
class GodotStringNamePrinter:
33
def __init__(self, value):
34
self.value = value
35
36
def to_string(self):
37
return self.value["_data"]["name"]["_cowdata"]["_ptr"]
38
39
# Hint that the object is string-like.
40
def display_hint(self):
41
return "string"
42
43
44
# Printer for Godot String variables.
45
class GodotStringPrinter:
46
def __init__(self, value):
47
self.value = value
48
49
def to_string(self):
50
return self.value["_cowdata"]["_ptr"]
51
52
# Hint that the object is string-like.
53
def display_hint(self):
54
return "string"
55
56
57
# Printer for Godot Vector variables.
58
class GodotVectorPrinter:
59
def __init__(self, value):
60
self.value = value
61
62
# The COW (Copy On Write) object does a bunch of pointer arithmetic to access
63
# its members.
64
# The offsets are constants on the C++ side, optimized out, so not accessible to us.
65
# I'll just hard code the observed values and hope they are the same forever.
66
# See core/templates/cowdata.h
67
SIZE_OFFSET = 8
68
DATA_OFFSET = 16
69
70
# Figures out the number of elements in the vector.
71
def get_size(self):
72
cowdata = self.value["_cowdata"]
73
if cowdata["_ptr"] == 0:
74
return 0
75
else:
76
# The ptr member of cowdata does not point to the beginning of the
77
# cowdata. It points to the beginning of the data section of the cowdata.
78
# To get to the length section, we must back up to the beginning of the struct,
79
# then move back forward to the size.
80
# cf. CowData::_get_size
81
ptr = cowdata["_ptr"].cast(gdb.lookup_type("uint8_t").pointer())
82
return int((ptr - self.DATA_OFFSET + self.SIZE_OFFSET).dereference())
83
84
# Lists children of the value, in this case the vector's items.
85
def children(self):
86
# Return nothing if ptr is null.
87
ptr = self.value["_cowdata"]["_ptr"]
88
if ptr == 0:
89
return
90
# Yield the items one by one.
91
for i in range(self.get_size()):
92
yield str(i), (ptr + i).dereference()
93
94
def to_string(self):
95
return "%s [%d]" % (self.value.type.name, self.get_size())
96
97
# Hint that the object is array-like.
98
def display_hint(self):
99
return "array"
100
101
102
VECTOR_REGEX = re.compile("^Vector<.*$")
103
104
105
# Tries to find a pretty printer for a debugger value.
106
def lookup_pretty_printer(value):
107
if value.type.name == "StringName":
108
return GodotStringNamePrinter(value)
109
if value.type.name == "String":
110
return GodotStringPrinter(value)
111
if value.type.name and VECTOR_REGEX.match(value.type.name):
112
return GodotVectorPrinter(value)
113
return None
114
115
116
# Register our printer lookup function.
117
# The first parameter could be used to limit the scope of the printer
118
# to a specific object file, but that is unnecessary for us.
119
gdb.printing.register_pretty_printer(None, lookup_pretty_printer)
120
121