5
5
6
6
source .gdb.py
7
7
8
- Use
8
+ If needed, pretty printers can be by-passed by using the /r flag:
9
9
(gdb) p /r any_variable
10
- to print |any_variable| without using any printers.
10
+
11
+ Use |set print pretty| to enable multi-line printing and indentation:
12
+ (gdb) set print pretty on
13
+
14
+ Use |set print max-depth| to control the maximum print depth for nested
15
+ structures:
16
+ (gdb) set print pretty on
11
17
12
18
To interactively type Python for development of the printers, use
13
19
(gdb) python foo = gdb.parse_and_eval('bar')
@@ -32,7 +38,10 @@ def to_string(self):
32
38
33
39
def children (self ):
34
40
for field in self .val .type .fields ():
35
- yield (field .name , self .val [field .name ])
41
+ if field .name == 'val' :
42
+ yield ('val' , self .format_string ())
43
+ else :
44
+ yield (field .name , self .val [field .name ])
36
45
37
46
def format_string (self ):
38
47
len = int (self .val ['len' ])
@@ -49,14 +58,16 @@ def format_string(self):
49
58
str += ' (%d bytes total)' % int (self .val ['len' ])
50
59
51
60
return str
61
+
62
+
52
63
pp_set .add_printer ('zend_string' , '^_zend_string$' , ZendStringPrettyPrinter )
53
64
54
65
class ZendTypePrettyPrinter (gdb .printing .PrettyPrinter ):
55
66
"Print a zend_type"
56
67
57
68
def __init__ (self , val ):
58
69
self .val = val
59
- self . load_bits ()
70
+ load_type_bits ()
60
71
61
72
def to_string (self ):
62
73
return self .format_type (self .val )
@@ -73,7 +84,7 @@ def format_type(self, t):
73
84
meta = []
74
85
for bit in range (0 , type_mask_size ):
75
86
if type_mask & (1 << bit ):
76
- type_name = self . bits .get (bit )
87
+ type_name = type_bit_to_name .get (bit )
77
88
match type_name :
78
89
case None :
79
90
parts .append ('(1<<%d)' % bit )
@@ -104,34 +115,225 @@ def format_type(self, t):
104
115
105
116
return str
106
117
107
- def load_bits (self ):
108
- (symbol ,_ ) = gdb .lookup_symbol ("zend_gc_refcount" )
109
- if symbol == None :
110
- raise "Could not find zend_types.h: symbol zend_gc_refcount not found"
111
- filename = symbol .symtab .fullname ()
112
118
113
- bits = {}
119
+ pp_set .add_printer ('zend_type' , '^zend_type$' , ZendTypePrettyPrinter )
120
+
121
+ class ZendAstKindPrettyPrinter (gdb .printing .PrettyPrinter ):
122
+ "Print a zend_ast_kind"
123
+
124
+ def __init__ (self , val ):
125
+ self .val = val
126
+
127
+ def to_string (self ):
128
+ return self .val .cast (gdb .lookup_type ('enum _zend_ast_kind' ))
129
+
130
+
131
+ pp_set .add_printer ('zend_ast_kind' , '^zend_ast_kind$' , ZendAstKindPrettyPrinter )
132
+
133
+ class ZendAstPrettyPrinter (gdb .printing .PrettyPrinter ):
134
+ "Print a zend_ast"
135
+
136
+ def __init__ (self , val ):
137
+ self .val = val
138
+
139
+ def to_string (self ):
140
+ return '((%s*)0x%x)' % (str (self .cast ().type ), self .val .address )
141
+
142
+ def children (self ):
143
+ val = self .cast ()
144
+ for field in val .type .fields ():
145
+ if field .name == 'child' :
146
+ children = val [field .name ]
147
+ num_children = self .num_children ()
148
+
149
+ ptr_type = gdb .lookup_type ('zend_ast' ).pointer ().pointer ()
150
+ children = children .cast (ptr_type )
151
+
152
+ for i in range (0 , num_children ):
153
+ c = children [i ]
154
+ if int (c ) != 0 :
155
+ c = c .dereference ()
156
+ yield ('child[%d]' % i , c )
157
+ elif field .name == 'name' :
158
+ yield (field .name , ZendStringPrettyPrinter (val [field .name ].dereference ()).to_string ())
159
+ elif field .name == 'val' :
160
+ yield (field .name , ZvalPrettyPrinter (val [field .name ]).to_string ())
161
+ else :
162
+ yield (field .name , val [field .name ])
163
+
164
+ def is_special (self ):
165
+ special_shift = 6 # ZEND_AST_SPECIAL_SHIFT
166
+ kind = self .val ['kind' ]
167
+ return (kind >> special_shift ) & 1
168
+
169
+ def is_decl (self ):
170
+ return self .is_special () and int (self .val ['kind' ]) >= enum_value ('ZEND_AST_FUNC_DECL' )
171
+
172
+ def is_list (self ):
173
+ list_shift = 7 # ZEND_AST_IS_LIST_SHIFT
174
+ kind = self .val ['kind' ]
175
+ return (kind >> list_shift ) & 1
114
176
115
- with open ( filename , 'r' ) as file :
116
- content = file . read ( )
177
+ def cast ( self ) :
178
+ kind = int ( self . val [ 'kind' ] )
117
179
118
- pattern = re .compile (r'#define _ZEND_TYPE_([^\s]+)_BIT\s+\(1u << (\d+)\)' )
119
- matches = pattern .findall (content )
120
- for name , bit in matches :
180
+ if kind == enum_value ('ZEND_AST_ZVAL' ) or kind == enum_value ('ZEND_AST_CONSTANT' ):
181
+ return self .val .cast (gdb .lookup_type ('zend_ast_zval' ))
182
+ if kind == enum_value ('ZEND_AST_ZNODE' ):
183
+ return self .val .cast (gdb .lookup_type ('zend_ast_znode' ))
184
+ if self .is_decl ():
185
+ return self .val .cast (gdb .lookup_type ('zend_ast_decl' ))
186
+ if self .is_list ():
187
+ return self .val .cast (gdb .lookup_type ('zend_ast_list' ))
188
+
189
+ return self .val
190
+
191
+ def num_children (self ):
192
+ if self .is_decl ():
193
+ decl_type = gdb .lookup_type ('zend_ast_decl' )
194
+ child_type = decl_type ['child' ].type
195
+ return array_size (child_type )
196
+ if self .is_special ():
197
+ return 0
198
+ elif self .is_list ():
199
+ return int (self .cast ()['children' ])
200
+ else :
201
+ num_children_shift = 8 # ZEND_AST_NUM_CHILDREN_SHIFT
202
+ kind = self .val ['kind' ]
203
+ return kind >> num_children_shift
204
+
205
+
206
+ pp_set .add_printer ('zend_ast' , '^_zend_ast$' , ZendAstPrettyPrinter )
207
+
208
+ class ZvalPrettyPrinter (gdb .printing .PrettyPrinter ):
209
+ "Print a zval"
210
+
211
+ def __init__ (self , val ):
212
+ self .val = val
213
+ load_type_bits ()
214
+
215
+ def to_string (self ):
216
+ return self .value_to_string ()
217
+
218
+ def value_to_string (self ):
219
+ t = int (self .val ['u1' ]['v' ]['type' ])
220
+ if t == type_name_to_bit ['undef' ]:
221
+ return 'undef'
222
+ elif t == type_name_to_bit ['null' ]:
223
+ return 'null'
224
+ elif t == type_name_to_bit ['false' ]:
225
+ return 'false'
226
+ elif t == type_name_to_bit ['true' ]:
227
+ return 'true'
228
+ elif t == type_name_to_bit ['long' ]:
229
+ return str (self .val ['value' ]['lval' ])
230
+ elif t == type_name_to_bit ['double' ]:
231
+ return str (self .val ['value' ]['dval' ])
232
+ elif t == type_name_to_bit ['string' ]:
233
+ return ZendStringPrettyPrinter (self .val ['value' ]['str' ].dereference ()).to_string ()
234
+ elif t == type_name_to_bit ['array' ]:
235
+ return 'array'
236
+ elif t == type_name_to_bit ['object' ]:
237
+ return 'object(%s)' % ZendStringPrettyPrinter (self .val ['value' ]['obj' ]['ce' ]['name' ].dereference ()).to_string ()
238
+ elif t == type_name_to_bit ['resource' ]:
239
+ return 'resource'
240
+ elif t == type_name_to_bit ['reference' ]:
241
+ return 'reference'
242
+ elif t == type_name_to_bit ['constant_ast' ]:
243
+ return 'constant_ast'
244
+ else :
245
+ return 'zval of type %d' % int (self .val ['u1' ]['v' ]['type' ])
246
+
247
+ def children (self ):
248
+ for field in self .val .type .fields ():
249
+ if field .name == 'value' :
250
+ value = self .val ['value' ]
251
+ t = int (self .val ['u1' ]['v' ]['type' ])
252
+ if t == type_name_to_bit ['undef' ]:
253
+ value = value ['lval' ]
254
+ elif t == type_name_to_bit ['null' ]:
255
+ value = value ['lval' ]
256
+ elif t == type_name_to_bit ['false' ]:
257
+ value = value ['lval' ]
258
+ elif t == type_name_to_bit ['true' ]:
259
+ value = value ['lval' ]
260
+ elif t == type_name_to_bit ['long' ]:
261
+ value = value ['lval' ]
262
+ elif t == type_name_to_bit ['double' ]:
263
+ value = value ['dval' ]
264
+ elif t == type_name_to_bit ['string' ]:
265
+ value = value ['str' ].dereference ()
266
+ elif t == type_name_to_bit ['array' ]:
267
+ value = value ['ht' ].dereference ()
268
+ elif t == type_name_to_bit ['object' ]:
269
+ value = value ['obj' ].dereference ()
270
+ elif t == type_name_to_bit ['resource' ]:
271
+ value = value ['res' ].dereference ()
272
+ elif t == type_name_to_bit ['reference' ]:
273
+ value = value ['ref' ].dereference ()
274
+ elif t == type_name_to_bit ['constant_ast' ]:
275
+ value = value ['ast' ].dereference ()
276
+ else :
277
+ value = value ['ptr' ]
278
+ yield (field .name , value )
279
+ elif field .name == 'u2' :
280
+ yield ('u2' , self .val [field .name ]['extra' ])
281
+ else :
282
+ yield (field .name , self .val [field .name ])
283
+
284
+
285
+ pp_set .add_printer ('zval' , '^_zval_struct$' , ZvalPrettyPrinter )
286
+
287
+ type_bit_to_name = None
288
+ type_name_to_bit = None
289
+
290
+ def load_type_bits ():
291
+ global type_bit_to_name
292
+ global type_name_to_bit
293
+
294
+ if type_bit_to_name != None :
295
+ return
296
+
297
+ (symbol ,_ ) = gdb .lookup_symbol ("zend_gc_refcount" )
298
+ if symbol == None :
299
+ raise "Could not find zend_types.h: symbol zend_gc_refcount not found"
300
+ filename = symbol .symtab .fullname ()
301
+
302
+ bits = {}
303
+
304
+ with open (filename , 'r' ) as file :
305
+ content = file .read ()
306
+
307
+ pattern = re .compile (r'#define _ZEND_TYPE_([^\s]+)_BIT\s+\(1u << (\d+)\)' )
308
+ matches = pattern .findall (content )
309
+ for name , bit in matches :
310
+ bits [int (bit )] = name .lower ()
311
+
312
+ pattern = re .compile (r'#define IS_([^\s]+)\s+(\d+)' )
313
+ matches = pattern .findall (content )
314
+ for name , bit in matches :
315
+ if not int (bit ) in bits :
121
316
bits [int (bit )] = name .lower ()
122
317
123
- pattern = re .compile (r'#define IS_([^\s]+)\s+(\d+)' )
124
- matches = pattern .findall (content )
125
- for name , bit in matches :
126
- if not int (bit ) in bits :
127
- bits [int (bit )] = name .lower ()
318
+ types = {}
319
+ for bit in bits :
320
+ types [bits [bit ]] = bit
128
321
129
- types = {}
130
- for bit in bits :
131
- types [bits [bit ]] = bit
322
+ type_bit_to_name = bits
323
+ type_name_to_bit = types
132
324
133
- self .bits = bits
134
- self .types = types
135
- pp_set .add_printer ('zend_type' , '^zend_type$' , ZendTypePrettyPrinter )
325
+ def lookup_symbol (name ):
326
+ (symbol , _ ) = gdb .lookup_symbol (name )
327
+ if symbol == None :
328
+ raise Exception ("Could not lookup symbol %s" % name )
329
+ return symbol
330
+
331
+ def enum_value (name ):
332
+ symbol = lookup_symbol (name )
333
+ return int (symbol .value ())
334
+
335
+ def array_size (ary_type ):
336
+ # array types have a single field whose type represents its range
337
+ return ary_type .fields ()[0 ].type .range ()[1 ]+ 1
136
338
137
339
gdb .printing .register_pretty_printer (gdb , pp_set , replace = True )
0 commit comments