1# Copyright (C) 2008-2020 Free Software Foundation, Inc. 2 3# This program is free software; you can redistribute it and/or modify 4# it under the terms of the GNU General Public License as published by 5# the Free Software Foundation; either version 3 of the License, or 6# (at your option) any later version. 7# 8# This program is distributed in the hope that it will be useful, 9# but WITHOUT ANY WARRANTY; without even the implied warranty of 10# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11# GNU General Public License for more details. 12# 13# You should have received a copy of the GNU General Public License 14# along with this program. If not, see <http://www.gnu.org/licenses/>. 15 16# This file is part of the GDB testsuite. It tests python pretty 17# printers. 18 19import re 20import gdb 21 22def _iterator (pointer, len): 23 start = pointer 24 end = pointer + len 25 while pointer != end: 26 yield ('[%d]' % int (pointer - start), pointer.dereference()) 27 pointer += 1 28 29# Same as _iterator but can be told to raise an exception. 30def _iterator_except (pointer, len): 31 start = pointer 32 end = pointer + len 33 while pointer != end: 34 if exception_flag: 35 raise gdb.MemoryError ('hi bob') 36 yield ('[%d]' % int (pointer - start), pointer.dereference()) 37 pointer += 1 38 39# Test returning a Value from a printer. 40class string_print (object): 41 def __init__(self, val): 42 self.val = val 43 44 def to_string(self): 45 return self.val['whybother']['contents'] 46 47# Test a class-based printer. 48class ContainerPrinter (object): 49 50 def __init__(self, val): 51 self.val = val 52 53 def to_string(self): 54 return 'container %s with %d elements' % (self.val['name'], self.val['len']) 55 56 def children(self): 57 return _iterator(self.val['elements'], self.val['len']) 58 59 def display_hint (self): 60 if (self.val['is_map_p']): 61 return 'map' 62 else: 63 return None 64 65# Treats a container as array. 66class ArrayPrinter (object): 67 def __init__(self, val): 68 self.val = val 69 70 def to_string(self): 71 return 'array %s with %d elements' % (self.val['name'], self.val['len']) 72 73 def children(self): 74 return _iterator(self.val['elements'], self.val['len']) 75 76 def display_hint (self): 77 return 'array' 78 79# Flag to make NoStringContainerPrinter throw an exception. 80exception_flag = False 81 82# Test a printer where to_string is None 83class NoStringContainerPrinter (object): 84 def __init__(self, val): 85 self.val = val 86 87 def to_string(self): 88 return None 89 90 def children(self): 91 return _iterator_except (self.val['elements'], self.val['len']) 92 93# See ToStringReturnsValueWrapper. 94class ToStringReturnsValueInner: 95 96 def __init__(self, val): 97 self.val = val 98 99 def to_string(self): 100 return 'Inner to_string {}'.format(int(self.val['val'])) 101 102# Test a printer that returns a gdb.Value in its to_string. That gdb.Value 103# also has its own pretty-printer. 104class ToStringReturnsValueWrapper: 105 106 def __init__(self, val): 107 self.val = val 108 109 def to_string(self): 110 return self.val['inner'] 111 112class pp_s (object): 113 def __init__(self, val): 114 self.val = val 115 116 def to_string(self): 117 a = self.val["a"] 118 b = self.val["b"] 119 if a.address != b: 120 raise Exception("&a(%s) != b(%s)" % (str(a.address), str(b))) 121 return " a=<" + str(self.val["a"]) + "> b=<" + str(self.val["b"]) + ">" 122 123class pp_ss (object): 124 def __init__(self, val): 125 self.val = val 126 127 def to_string(self): 128 return "a=<" + str(self.val["a"]) + "> b=<" + str(self.val["b"]) + ">" 129 130class pp_sss (object): 131 def __init__(self, val): 132 self.val = val 133 134 def to_string(self): 135 return "a=<" + str(self.val['a']) + "> b=<" + str(self.val["b"]) + ">" 136 137class pp_multiple_virtual (object): 138 def __init__ (self, val): 139 self.val = val 140 141 def to_string (self): 142 return "pp value variable is: " + str (self.val['value']) 143 144class pp_vbase1 (object): 145 def __init__ (self, val): 146 self.val = val 147 148 def to_string (self): 149 return "pp class name: " + self.val.type.tag 150 151class pp_nullstr (object): 152 def __init__(self, val): 153 self.val = val 154 155 def to_string(self): 156 return self.val['s'].string(gdb.target_charset()) 157 158class pp_ns (object): 159 "Print a std::basic_string of some kind" 160 161 def __init__(self, val): 162 self.val = val 163 164 def to_string(self): 165 len = self.val['length'] 166 return self.val['null_str'].string (gdb.target_charset(), length = len) 167 168 def display_hint (self): 169 return 'string' 170 171pp_ls_encoding = None 172 173class pp_ls (object): 174 "Print a std::basic_string of some kind" 175 176 def __init__(self, val): 177 self.val = val 178 179 def to_string(self): 180 length = self.val['len'] 181 if pp_ls_encoding is not None: 182 if length >= 0: 183 return self.val['lazy_str'].lazy_string( 184 encoding = pp_ls_encoding, 185 length = length) 186 else: 187 return self.val['lazy_str'].lazy_string( 188 encoding = pp_ls_encoding) 189 else: 190 if length >= 0: 191 return self.val['lazy_str'].lazy_string(length = length) 192 else: 193 return self.val['lazy_str'].lazy_string() 194 195 def display_hint (self): 196 return 'string' 197 198class pp_hint_error (object): 199 "Throw error from display_hint" 200 201 def __init__(self, val): 202 self.val = val 203 204 def to_string(self): 205 return 'hint_error_val' 206 207 def display_hint (self): 208 raise Exception("hint failed") 209 210class pp_children_as_list (object): 211 "Throw error from display_hint" 212 213 def __init__(self, val): 214 self.val = val 215 216 def to_string(self): 217 return 'children_as_list_val' 218 219 def children (self): 220 return [('one', 1)] 221 222class pp_outer (object): 223 "Print struct outer" 224 225 def __init__ (self, val): 226 self.val = val 227 228 def to_string (self): 229 return "x = %s" % self.val['x'] 230 231 def children (self): 232 yield 's', self.val['s'] 233 yield 'x', self.val['x'] 234 235class MemoryErrorString (object): 236 "Raise an error" 237 238 def __init__(self, val): 239 self.val = val 240 241 def to_string(self): 242 raise gdb.MemoryError ("Cannot access memory.") 243 244 def display_hint (self): 245 return 'string' 246 247class pp_eval_type (object): 248 def __init__(self, val): 249 self.val = val 250 251 def to_string(self): 252 gdb.execute("bt", to_string=True) 253 return "eval=<" + str(gdb.parse_and_eval("eval_func (123456789, 2, 3, 4, 5, 6, 7, 8)")) + ">" 254 255class pp_int_typedef (object): 256 def __init__(self, val): 257 self.val = val 258 259 def to_string(self): 260 return "type=%s, val=%s" % (self.val.type, int(self.val)) 261 262class pp_int_typedef3 (object): 263 "A printer without a to_string method" 264 265 def __init__(self, val): 266 self.val = val 267 268 def children(self): 269 yield 's', 27 270 271def lookup_function (val): 272 "Look-up and return a pretty-printer that can print val." 273 274 # Get the type. 275 type = val.type 276 277 # If it points to a reference, get the reference. 278 if type.code == gdb.TYPE_CODE_REF: 279 type = type.target () 280 281 # Get the unqualified type, stripped of typedefs. 282 type = type.unqualified ().strip_typedefs () 283 284 # Get the type name. 285 typename = type.tag 286 287 if typename == None: 288 return None 289 290 # Iterate over local dictionary of types to determine 291 # if a printer is registered for that type. Return an 292 # instantiation of the printer if found. 293 for function in pretty_printers_dict: 294 if function.match (typename): 295 return pretty_printers_dict[function] (val) 296 297 # Cannot find a pretty printer. Return None. 298 299 return None 300 301def disable_lookup_function (): 302 lookup_function.enabled = False 303 304def enable_lookup_function (): 305 lookup_function.enabled = True 306 307# Lookup a printer for VAL in the typedefs dict. 308def lookup_typedefs_function (val): 309 "Look-up and return a pretty-printer that can print val (typedefs)." 310 311 # Get the type. 312 type = val.type 313 314 if type == None or type.name == None or type.code != gdb.TYPE_CODE_TYPEDEF: 315 return None 316 317 # Iterate over local dictionary of typedef types to determine if a 318 # printer is registered for that type. Return an instantiation of 319 # the printer if found. 320 for function in typedefs_pretty_printers_dict: 321 if function.match (type.name): 322 return typedefs_pretty_printers_dict[function] (val) 323 324 # Cannot find a pretty printer. 325 return None 326 327def register_pretty_printers (): 328 pretty_printers_dict[re.compile ('^struct s$')] = pp_s 329 pretty_printers_dict[re.compile ('^s$')] = pp_s 330 pretty_printers_dict[re.compile ('^S$')] = pp_s 331 332 pretty_printers_dict[re.compile ('^struct ss$')] = pp_ss 333 pretty_printers_dict[re.compile ('^ss$')] = pp_ss 334 pretty_printers_dict[re.compile ('^const S &$')] = pp_s 335 pretty_printers_dict[re.compile ('^SSS$')] = pp_sss 336 337 pretty_printers_dict[re.compile ('^VirtualTest$')] = pp_multiple_virtual 338 pretty_printers_dict[re.compile ('^Vbase1$')] = pp_vbase1 339 340 pretty_printers_dict[re.compile ('^struct nullstr$')] = pp_nullstr 341 pretty_printers_dict[re.compile ('^nullstr$')] = pp_nullstr 342 343 # Note that we purposely omit the typedef names here. 344 # Printer lookup is based on canonical name. 345 # However, we do need both tagged and untagged variants, to handle 346 # both the C and C++ cases. 347 pretty_printers_dict[re.compile ('^struct string_repr$')] = string_print 348 pretty_printers_dict[re.compile ('^struct container$')] = ContainerPrinter 349 pretty_printers_dict[re.compile ('^struct justchildren$')] = NoStringContainerPrinter 350 pretty_printers_dict[re.compile ('^string_repr$')] = string_print 351 pretty_printers_dict[re.compile ('^container$')] = ContainerPrinter 352 pretty_printers_dict[re.compile ('^justchildren$')] = NoStringContainerPrinter 353 354 pretty_printers_dict[re.compile ('^struct to_string_returns_value_inner$')] = ToStringReturnsValueInner 355 pretty_printers_dict[re.compile ('^to_string_returns_value_inner$')] = ToStringReturnsValueInner 356 pretty_printers_dict[re.compile ('^struct to_string_returns_value_wrapper$')] = ToStringReturnsValueWrapper 357 pretty_printers_dict[re.compile ('^to_string_returns_value_wrapper$')] = ToStringReturnsValueWrapper 358 359 pretty_printers_dict[re.compile ('^struct ns$')] = pp_ns 360 pretty_printers_dict[re.compile ('^ns$')] = pp_ns 361 362 pretty_printers_dict[re.compile ('^struct lazystring$')] = pp_ls 363 pretty_printers_dict[re.compile ('^lazystring$')] = pp_ls 364 365 pretty_printers_dict[re.compile ('^struct outerstruct$')] = pp_outer 366 pretty_printers_dict[re.compile ('^outerstruct$')] = pp_outer 367 368 pretty_printers_dict[re.compile ('^struct hint_error$')] = pp_hint_error 369 pretty_printers_dict[re.compile ('^hint_error$')] = pp_hint_error 370 371 pretty_printers_dict[re.compile ('^struct children_as_list$')] = pp_children_as_list 372 pretty_printers_dict[re.compile ('^children_as_list$')] = pp_children_as_list 373 374 pretty_printers_dict[re.compile ('^memory_error$')] = MemoryErrorString 375 376 pretty_printers_dict[re.compile ('^eval_type_s$')] = pp_eval_type 377 378 typedefs_pretty_printers_dict[re.compile ('^int_type$')] = pp_int_typedef 379 typedefs_pretty_printers_dict[re.compile ('^int_type2$')] = pp_int_typedef 380 typedefs_pretty_printers_dict[re.compile ('^int_type3$')] = pp_int_typedef3 381 382# Dict for struct types with typedefs fully stripped. 383pretty_printers_dict = {} 384# Dict for typedef types. 385typedefs_pretty_printers_dict = {} 386 387register_pretty_printers () 388gdb.pretty_printers.append (lookup_function) 389gdb.pretty_printers.append (lookup_typedefs_function) 390