blob: d98c9d97fc320c802d0eebc35485fa4bf6d968f6 [file] [log] [blame]
Austin Engcc2516a2023-10-17 20:57:54 +00001# Copyright 2022 The Dawn & Tint Authors
Antonio Maiorano14b5fb62022-10-27 20:17:45 +00002#
Austin Engcc2516a2023-10-17 20:57:54 +00003# Redistribution and use in source and binary forms, with or without
4# modification, are permitted provided that the following conditions are met:
Antonio Maiorano14b5fb62022-10-27 20:17:45 +00005#
Austin Engcc2516a2023-10-17 20:57:54 +00006# 1. Redistributions of source code must retain the above copyright notice, this
7# list of conditions and the following disclaimer.
Antonio Maiorano14b5fb62022-10-27 20:17:45 +00008#
Austin Engcc2516a2023-10-17 20:57:54 +00009# 2. Redistributions in binary form must reproduce the above copyright notice,
10# this list of conditions and the following disclaimer in the documentation
11# and/or other materials provided with the distribution.
12#
13# 3. Neither the name of the copyright holder nor the names of its
14# contributors may be used to endorse or promote products derived from
15# this software without specific prior written permission.
16#
17# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
21# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
23# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
24# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
25# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Antonio Maiorano14b5fb62022-10-27 20:17:45 +000027
28# Pretty printers for the Tint project.
29# Add a line to your ~/.gdbinit to source this file, e.g.:
30#
31# source /path/to/dawn/src/tint/tint_gdb.py
32
33import gdb
34import gdb.printing
35from itertools import chain
36
37# When debugging this module, set _DEBUGGING = True so that re-sourcing this file in gdb replaces
38# the existing printers.
39_DEBUGGING = True
40
41# Enable to display other data members along with child elements of compound data types (arrays, etc.).
42# This is useful in debuggers like VS Code that doesn't display the `to_string()` result in the watch window.
43# OTOH, it's less useful when using gdb/lldb's print command.
44_DISPLAY_MEMBERS_AS_CHILDREN = False
45
46
47# Tips for debugging using VS Code:
48# - Set a breakpoint where you can view the types you want to debug/write pretty printers for.
49# - Debug Console: source /path/to/dawn/src/tint/tint_gdb.py
50# - To execute Python code, in the Debug Console:
51# -exec python foo = gdb.parse_and_eval('map.set_')
52# -exec python v = (foo['slots_']['impl_']['slice']['data'] + 8).dereference()['value']
53#
54# - Useful docs:
55# Python API: https://sourceware.org/gdb/onlinedocs/gdb/Python-API.html#Python-API
56# Especially:
57# Types: https://sourceware.org/gdb/onlinedocs/gdb/Types-In-Python.html#Types-In-Python
58# Values: https://sourceware.org/gdb/onlinedocs/gdb/Values-From-Inferior.html#Values-From-Inferior
59
60
61pp_set = gdb.printing.RegexpCollectionPrettyPrinter("tint")
62
63
64class Printer(object):
65 '''Base class for Printers'''
66
67 def __init__(self, val):
68 self.val = val
69
70 def template_type(self, index):
71 '''Returns template type at index'''
72 return self.val.type.template_argument(index)
73
74
75class UtilsSlicePrinter(Printer):
dan sinclairbae54e72023-07-28 15:01:54 +000076 '''Printer for tint::Slice<T>'''
Antonio Maiorano14b5fb62022-10-27 20:17:45 +000077
78 def __init__(self, val):
79 super(UtilsSlicePrinter, self).__init__(val)
80 self.len = self.val['len']
81 self.cap = self.val['cap']
82 self.data = self.val['data']
83 self.elem_type = self.data.type.target().unqualified()
84
85 def length(self):
86 return self.len
87
88 def value_at(self, index):
89 '''Returns array value at index'''
90 return (self.data + index).dereference().cast(self.elem_type)
91
92 def to_string(self):
93 return 'length={} capacity={}'.format(self.len, self.cap)
94
95 def members(self):
96 if _DISPLAY_MEMBERS_AS_CHILDREN:
97 return [
98 ('length', self.len),
99 ('capacity', self.cap),
100 ]
101 else:
102 return []
103
104 def children(self):
105 for m in self.members():
106 yield m
107 for i in range(self.len):
108 yield str(i), self.value_at(i)
109
110 def display_hint(self):
111 return 'array'
112
113
dan sinclairbae54e72023-07-28 15:01:54 +0000114pp_set.add_printer('UtilsSlicePrinter', '^tint::Slice<.*>$', UtilsSlicePrinter)
Antonio Maiorano14b5fb62022-10-27 20:17:45 +0000115
116
117class UtilsVectorPrinter(Printer):
dan sinclairbae54e72023-07-28 15:01:54 +0000118 '''Printer for tint::Vector<T, N>'''
Antonio Maiorano14b5fb62022-10-27 20:17:45 +0000119
120 def __init__(self, val):
121 super(UtilsVectorPrinter, self).__init__(val)
122 self.slice = self.val['impl_']['slice']
123 self.using_heap = self.slice['cap'] > self.template_type(1)
124
125 def slice_printer(self):
126 return UtilsSlicePrinter(self.slice)
127
128 def to_string(self):
129 return 'heap={} {}'.format(self.using_heap, self.slice)
130
131 def members(self):
132 if _DISPLAY_MEMBERS_AS_CHILDREN:
133 return [
134 ('heap', self.using_heap),
135 ]
136 else:
137 return []
138
139 def children(self):
140 return chain(self.members(), self.slice_printer().children())
141
142 def display_hint(self):
143 return 'array'
144
145
dan sinclairbae54e72023-07-28 15:01:54 +0000146pp_set.add_printer('UtilsVector', '^tint::Vector<.*>$', UtilsVectorPrinter)
Antonio Maiorano14b5fb62022-10-27 20:17:45 +0000147
148
149class UtilsVectorRefPrinter(Printer):
dan sinclairbae54e72023-07-28 15:01:54 +0000150 '''Printer for tint::VectorRef<T>'''
Antonio Maiorano14b5fb62022-10-27 20:17:45 +0000151
152 def __init__(self, val):
153 super(UtilsVectorRefPrinter, self).__init__(val)
154 self.slice = self.val['slice_']
155 self.can_move = self.val['can_move_']
156
157 def to_string(self):
158 return 'can_move={} {}'.format(self.can_move, self.slice)
159
160 def members(self):
161 if _DISPLAY_MEMBERS_AS_CHILDREN:
162 return [
163 ('can_move', self.can_move),
164 ]
165 else:
166 return []
167
168 def children(self):
169 return chain(self.members(), UtilsSlicePrinter(self.slice).children())
170
171 def display_hint(self):
172 return 'array'
173
174
dan sinclairbae54e72023-07-28 15:01:54 +0000175pp_set.add_printer('UtilsVector', '^tint::VectorRef<.*>$',
176 UtilsVectorRefPrinter)
Antonio Maiorano14b5fb62022-10-27 20:17:45 +0000177
178
Antonio Maioranoc027f332022-11-07 14:00:53 +0000179class UtilsHashmapBasePrinter(Printer):
180 '''Base Printer for HashmapBase-derived types'''
Antonio Maiorano14b5fb62022-10-27 20:17:45 +0000181
182 def __init__(self, val):
Antonio Maioranoc027f332022-11-07 14:00:53 +0000183 super(UtilsHashmapBasePrinter, self).__init__(val)
Antonio Maiorano14b5fb62022-10-27 20:17:45 +0000184 self.slice = UtilsVectorPrinter(self.val['slots_']).slice_printer()
185 self.try_read_std_optional_func = self.try_read_std_optional
186
187 def to_string(self):
188 length = 0
189 for slot in range(0, self.slice.length()):
190 v = self.slice.value_at(slot)
191 if v['hash'] != 0:
192 length += 1
193 return 'length={}'.format(length)
194
195 def children(self):
196 for slot in range(0, self.slice.length()):
197 v = self.slice.value_at(slot)
198 if v['hash'] != 0:
Antonio Maioranoc027f332022-11-07 14:00:53 +0000199 entry = v['entry']
Antonio Maiorano14b5fb62022-10-27 20:17:45 +0000200
Antonio Maioranoc027f332022-11-07 14:00:53 +0000201 # entry is a std::optional, let's try to extract its value for display
202 kvp = self.try_read_std_optional_func(slot, entry)
Antonio Maiorano14b5fb62022-10-27 20:17:45 +0000203 if kvp is None:
Antonio Maioranoc027f332022-11-07 14:00:53 +0000204 # If we failed, just output the slot and entry as is, which will use
Antonio Maiorano14b5fb62022-10-27 20:17:45 +0000205 # the default visualizer for each.
Antonio Maioranoc027f332022-11-07 14:00:53 +0000206 kvp = slot, entry
Antonio Maiorano14b5fb62022-10-27 20:17:45 +0000207
208 yield str(kvp[0]), kvp[1]
209
210 def display_hint(self):
211 return 'array'
212
Antonio Maioranoc027f332022-11-07 14:00:53 +0000213 def try_read_std_optional(self, slot, entry):
214 return None
215
216
217class UtilsHashsetPrinter(UtilsHashmapBasePrinter):
218 '''Printer for Hashset<T, N, HASH, EQUAL>'''
219
220 def try_read_std_optional(self, slot, entry):
Antonio Maiorano14b5fb62022-10-27 20:17:45 +0000221 try:
222 # libstdc++
Antonio Maioranoc027f332022-11-07 14:00:53 +0000223 v = entry['_M_payload']['_M_payload']['_M_value']
Antonio Maiorano14b5fb62022-10-27 20:17:45 +0000224 return slot, v
Antonio Maiorano14b5fb62022-10-27 20:17:45 +0000225 except:
226 return None
227
228
dan sinclairbae54e72023-07-28 15:01:54 +0000229pp_set.add_printer('UtilsHashset', '^tint::Hashset<.*>$', UtilsHashsetPrinter)
Antonio Maiorano14b5fb62022-10-27 20:17:45 +0000230
231
Antonio Maioranoc027f332022-11-07 14:00:53 +0000232class UtilsHashmapPrinter(UtilsHashmapBasePrinter):
Antonio Maiorano14b5fb62022-10-27 20:17:45 +0000233 '''Printer for Hashmap<K, V, N, HASH, EQUAL>'''
234
Antonio Maioranoc027f332022-11-07 14:00:53 +0000235 def try_read_std_optional(self, slot, entry):
Antonio Maiorano14b5fb62022-10-27 20:17:45 +0000236 try:
237 # libstdc++
Antonio Maioranoc027f332022-11-07 14:00:53 +0000238 kvp = entry['_M_payload']['_M_payload']['_M_value']
Antonio Maiorano14b5fb62022-10-27 20:17:45 +0000239 return str(kvp['key']), kvp['value']
240 except:
Antonio Maioranoc027f332022-11-07 14:00:53 +0000241 return None
Antonio Maiorano14b5fb62022-10-27 20:17:45 +0000242
243
dan sinclairbae54e72023-07-28 15:01:54 +0000244pp_set.add_printer('UtilsHashmap', '^tint::Hashmap<.*>$', UtilsHashmapPrinter)
Antonio Maiorano14b5fb62022-10-27 20:17:45 +0000245
246
247gdb.printing.register_pretty_printer(gdb, pp_set, replace=_DEBUGGING)