@@ -131,10 +131,74 @@ def children(self):
131
131
def to_string (self ):
132
132
return 'llvm::Optional is %sinitialized' % ('' if self .value ['hasVal' ] else 'not ' )
133
133
134
+ class DenseMapPrinter :
135
+ "Print a DenseMap"
136
+
137
+ class _iterator :
138
+ def __init__ (self , key_info_t , begin , end ):
139
+ self .key_info_t = key_info_t
140
+ self .cur = begin
141
+ self .end = end
142
+ self .advancePastEmptyBuckets ()
143
+ self .first = True
144
+
145
+ def __iter__ (self ):
146
+ return self
147
+
148
+ def advancePastEmptyBuckets (self ):
149
+ # disabled until the comments below can be addressed
150
+ # keeping as notes/posterity/hints for future contributors
151
+ return
152
+ n = self .key_info_t .name
153
+ is_equal = gdb .parse_and_eval (n + '::isEqual' )
154
+ empty = gdb .parse_and_eval (n + '::getEmptyKey()' )
155
+ tombstone = gdb .parse_and_eval (n + '::getTombstoneKey()' )
156
+ # the following is invalid, GDB fails with:
157
+ # Python Exception <class 'gdb.error'> Attempt to take address of value
158
+ # not located in memory.
159
+ # because isEqual took parameter (for the unsigned long key I was testing)
160
+ # by const ref, and GDB
161
+ # It's also not entirely general - we should be accessing the "getFirst()"
162
+ # member function, not the 'first' member variable, but I've yet to figure
163
+ # out how to find/call member functions (especially (const) overloaded
164
+ # ones) on a gdb.Value.
165
+ while self .cur != self .end and (is_equal (self .cur .dereference ()['first' ], empty ) or is_equal (self .cur .dereference ()['first' ], tombstone )):
166
+ self .cur = self .cur + 1
167
+
168
+ def next (self ):
169
+ if self .cur == self .end :
170
+ raise StopIteration
171
+ cur = self .cur
172
+ v = cur .dereference ()['first' if self .first else 'second' ]
173
+ if not self .first :
174
+ self .cur = self .cur + 1
175
+ self .advancePastEmptyBuckets ()
176
+ self .first = True
177
+ else :
178
+ self .first = False
179
+ return 'x' , v
180
+
181
+ def __init__ (self , val ):
182
+ self .val = val
183
+
184
+ def children (self ):
185
+ t = self .val .type .template_argument (3 ).pointer ()
186
+ begin = self .val ['Buckets' ].cast (t )
187
+ end = (begin + self .val ['NumBuckets' ]).cast (t )
188
+ return self ._iterator (self .val .type .template_argument (2 ), begin , end )
189
+
190
+ def to_string (self ):
191
+ return 'llvm::DenseMap with %d elements' % (self .val ['NumEntries' ])
192
+
193
+ def display_hint (self ):
194
+ return 'map'
195
+
196
+
134
197
pp = gdb .printing .RegexpCollectionPrettyPrinter ("LLVMSupport" )
135
198
pp .add_printer ('llvm::SmallString' , '^llvm::SmallString<.*>$' , SmallStringPrinter )
136
199
pp .add_printer ('llvm::StringRef' , '^llvm::StringRef$' , StringRefPrinter )
137
200
pp .add_printer ('llvm::SmallVectorImpl' , '^llvm::SmallVector(Impl)?<.*>$' , SmallVectorPrinter )
138
201
pp .add_printer ('llvm::ArrayRef' , '^llvm::(Const)?ArrayRef<.*>$' , ArrayRefPrinter )
139
202
pp .add_printer ('llvm::Optional' , '^llvm::Optional<.*>$' , OptionalPrinter )
203
+ pp .add_printer ('llvm::DenseMap' , '^llvm::DenseMap<.*>$' , DenseMapPrinter )
140
204
gdb .printing .register_pretty_printer (gdb .current_objfile (), pp )
0 commit comments