Ben Cheng | d9735fc | 2013-08-22 22:10:54 -0700 | [diff] [blame] | 1 | # GDB 'explore' command. |
| 2 | # Copyright (C) 2012-2013 Free Software Foundation, Inc. |
| 3 | |
| 4 | # This program is free software; you can redistribute it and/or modify |
| 5 | # it under the terms of the GNU General Public License as published by |
| 6 | # the Free Software Foundation; either version 3 of the License, or |
| 7 | # (at your option) any later version. |
| 8 | # |
| 9 | # This program is distributed in the hope that it will be useful, |
| 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 12 | # GNU General Public License for more details. |
| 13 | # |
| 14 | # You should have received a copy of the GNU General Public License |
| 15 | # along with this program. If not, see <http://www.gnu.org/licenses/>. |
| 16 | |
| 17 | """Implementation of the GDB 'explore' command using the GDB Python API.""" |
| 18 | |
| 19 | import gdb |
| 20 | import sys |
| 21 | |
| 22 | if sys.version_info[0] > 2: |
| 23 | # Python 3 renamed raw_input to input |
| 24 | raw_input = input |
| 25 | |
| 26 | class Explorer(object): |
| 27 | """Internal class which invokes other explorers.""" |
| 28 | |
| 29 | # This map is filled by the Explorer.init_env() function |
| 30 | type_code_to_explorer_map = { } |
| 31 | |
| 32 | _SCALAR_TYPE_LIST = ( |
| 33 | gdb.TYPE_CODE_CHAR, |
| 34 | gdb.TYPE_CODE_INT, |
| 35 | gdb.TYPE_CODE_BOOL, |
| 36 | gdb.TYPE_CODE_FLT, |
| 37 | gdb.TYPE_CODE_VOID, |
| 38 | gdb.TYPE_CODE_ENUM, |
| 39 | ) |
| 40 | |
| 41 | @staticmethod |
| 42 | def guard_expr(expr): |
| 43 | length = len(expr) |
| 44 | guard = False |
| 45 | |
| 46 | if expr[0] == '(' and expr[length-1] == ')': |
| 47 | pass |
| 48 | else: |
| 49 | i = 0 |
| 50 | while i < length: |
| 51 | c = expr[i] |
| 52 | if (c == '_' or ('a' <= c and c <= 'z') or |
| 53 | ('A' <= c and c <= 'Z') or ('0' <= c and c <= '9')): |
| 54 | pass |
| 55 | else: |
| 56 | guard = True |
| 57 | break |
| 58 | i += 1 |
| 59 | |
| 60 | if guard: |
| 61 | return "(" + expr + ")" |
| 62 | else: |
| 63 | return expr |
| 64 | |
| 65 | @staticmethod |
| 66 | def explore_expr(expr, value, is_child): |
| 67 | """Main function to explore an expression value. |
| 68 | |
| 69 | Arguments: |
| 70 | expr: The expression string that is being explored. |
| 71 | value: The gdb.Value value of the expression. |
| 72 | is_child: Boolean value to indicate if the expression is a child. |
| 73 | An expression is a child if it is derived from the main |
| 74 | expression entered by the user. For example, if the user |
| 75 | entered an expression which evaluates to a struct, then |
| 76 | when exploring the fields of the struct, is_child is set |
| 77 | to True internally. |
| 78 | |
| 79 | Returns: |
| 80 | No return value. |
| 81 | """ |
| 82 | type_code = value.type.code |
| 83 | if type_code in Explorer.type_code_to_explorer_map: |
| 84 | explorer_class = Explorer.type_code_to_explorer_map[type_code] |
| 85 | while explorer_class.explore_expr(expr, value, is_child): |
| 86 | pass |
| 87 | else: |
| 88 | print ("Explorer for type '%s' not yet available.\n" % |
| 89 | str(value.type)) |
| 90 | |
| 91 | @staticmethod |
| 92 | def explore_type(name, datatype, is_child): |
| 93 | """Main function to explore a data type. |
| 94 | |
| 95 | Arguments: |
| 96 | name: The string representing the path to the data type being |
| 97 | explored. |
| 98 | datatype: The gdb.Type value of the data type being explored. |
| 99 | is_child: Boolean value to indicate if the name is a child. |
| 100 | A name is a child if it is derived from the main name |
| 101 | entered by the user. For example, if the user entered |
| 102 | the name of struct type, then when exploring the fields |
| 103 | of the struct, is_child is set to True internally. |
| 104 | |
| 105 | Returns: |
| 106 | No return value. |
| 107 | """ |
| 108 | type_code = datatype.code |
| 109 | if type_code in Explorer.type_code_to_explorer_map: |
| 110 | explorer_class = Explorer.type_code_to_explorer_map[type_code] |
| 111 | while explorer_class.explore_type(name, datatype, is_child): |
| 112 | pass |
| 113 | else: |
| 114 | print ("Explorer for type '%s' not yet available.\n" % |
| 115 | str(datatype)) |
| 116 | |
| 117 | @staticmethod |
| 118 | def init_env(): |
| 119 | """Initializes the Explorer environment. |
| 120 | This function should be invoked before starting any exploration. If |
| 121 | invoked before an exploration, it need not be invoked for subsequent |
| 122 | explorations. |
| 123 | """ |
| 124 | Explorer.type_code_to_explorer_map = { |
| 125 | gdb.TYPE_CODE_CHAR : ScalarExplorer, |
| 126 | gdb.TYPE_CODE_INT : ScalarExplorer, |
| 127 | gdb.TYPE_CODE_BOOL : ScalarExplorer, |
| 128 | gdb.TYPE_CODE_FLT : ScalarExplorer, |
| 129 | gdb.TYPE_CODE_VOID : ScalarExplorer, |
| 130 | gdb.TYPE_CODE_ENUM : ScalarExplorer, |
| 131 | gdb.TYPE_CODE_STRUCT : CompoundExplorer, |
| 132 | gdb.TYPE_CODE_UNION : CompoundExplorer, |
| 133 | gdb.TYPE_CODE_PTR : PointerExplorer, |
| 134 | gdb.TYPE_CODE_REF : ReferenceExplorer, |
| 135 | gdb.TYPE_CODE_TYPEDEF : TypedefExplorer, |
| 136 | gdb.TYPE_CODE_ARRAY : ArrayExplorer |
| 137 | } |
| 138 | |
| 139 | @staticmethod |
| 140 | def is_scalar_type(type): |
| 141 | """Checks whether a type is a scalar type. |
| 142 | A type is a scalar type of its type is |
| 143 | gdb.TYPE_CODE_CHAR or |
| 144 | gdb.TYPE_CODE_INT or |
| 145 | gdb.TYPE_CODE_BOOL or |
| 146 | gdb.TYPE_CODE_FLT or |
| 147 | gdb.TYPE_CODE_VOID or |
| 148 | gdb.TYPE_CODE_ENUM. |
| 149 | |
| 150 | Arguments: |
| 151 | type: The type to be checked. |
| 152 | |
| 153 | Returns: |
| 154 | 'True' if 'type' is a scalar type. 'False' otherwise. |
| 155 | """ |
| 156 | return type.code in Explorer._SCALAR_TYPE_LIST |
| 157 | |
| 158 | @staticmethod |
| 159 | def return_to_parent_value(): |
| 160 | """A utility function which prints that the current exploration session |
| 161 | is returning to the parent value. Useful when exploring values. |
| 162 | """ |
| 163 | print ("\nReturning to parent value...\n") |
| 164 | |
| 165 | @staticmethod |
| 166 | def return_to_parent_value_prompt(): |
| 167 | """A utility function which prompts the user to press the 'enter' key |
| 168 | so that the exploration session can shift back to the parent value. |
| 169 | Useful when exploring values. |
| 170 | """ |
| 171 | raw_input("\nPress enter to return to parent value: ") |
| 172 | |
| 173 | @staticmethod |
| 174 | def return_to_enclosing_type(): |
| 175 | """A utility function which prints that the current exploration session |
| 176 | is returning to the enclosing type. Useful when exploring types. |
| 177 | """ |
| 178 | print ("\nReturning to enclosing type...\n") |
| 179 | |
| 180 | @staticmethod |
| 181 | def return_to_enclosing_type_prompt(): |
| 182 | """A utility function which prompts the user to press the 'enter' key |
| 183 | so that the exploration session can shift back to the enclosing type. |
| 184 | Useful when exploring types. |
| 185 | """ |
| 186 | raw_input("\nPress enter to return to enclosing type: ") |
| 187 | |
| 188 | |
| 189 | class ScalarExplorer(object): |
| 190 | """Internal class used to explore scalar values.""" |
| 191 | |
| 192 | @staticmethod |
| 193 | def explore_expr(expr, value, is_child): |
| 194 | """Function to explore scalar values. |
| 195 | See Explorer.explore_expr and Explorer.is_scalar_type for more |
| 196 | information. |
| 197 | """ |
| 198 | print ("'%s' is a scalar value of type '%s'." % |
| 199 | (expr, value.type)) |
| 200 | print ("%s = %s" % (expr, str(value))) |
| 201 | |
| 202 | if is_child: |
| 203 | Explorer.return_to_parent_value_prompt() |
| 204 | Explorer.return_to_parent_value() |
| 205 | |
| 206 | return False |
| 207 | |
| 208 | @staticmethod |
| 209 | def explore_type(name, datatype, is_child): |
| 210 | """Function to explore scalar types. |
| 211 | See Explorer.explore_type and Explorer.is_scalar_type for more |
| 212 | information. |
| 213 | """ |
| 214 | if datatype.code == gdb.TYPE_CODE_ENUM: |
| 215 | if is_child: |
| 216 | print ("%s is of an enumerated type '%s'." % |
| 217 | (name, str(datatype))) |
| 218 | else: |
| 219 | print ("'%s' is an enumerated type." % name) |
| 220 | else: |
| 221 | if is_child: |
| 222 | print ("%s is of a scalar type '%s'." % |
| 223 | (name, str(datatype))) |
| 224 | else: |
| 225 | print ("'%s' is a scalar type." % name) |
| 226 | |
| 227 | if is_child: |
| 228 | Explorer.return_to_enclosing_type_prompt() |
| 229 | Explorer.return_to_enclosing_type() |
| 230 | |
| 231 | return False |
| 232 | |
| 233 | |
| 234 | class PointerExplorer(object): |
| 235 | """Internal class used to explore pointer values.""" |
| 236 | |
| 237 | @staticmethod |
| 238 | def explore_expr(expr, value, is_child): |
| 239 | """Function to explore pointer values. |
| 240 | See Explorer.explore_expr for more information. |
| 241 | """ |
| 242 | print ("'%s' is a pointer to a value of type '%s'" % |
| 243 | (expr, str(value.type.target()))) |
| 244 | option = raw_input("Continue exploring it as a pointer to a single " |
| 245 | "value [y/n]: ") |
| 246 | if option == "y": |
| 247 | deref_value = None |
| 248 | try: |
| 249 | deref_value = value.dereference() |
| 250 | str(deref_value) |
| 251 | except gdb.MemoryError: |
| 252 | print ("'%s' a pointer pointing to an invalid memory " |
| 253 | "location." % expr) |
| 254 | if is_child: |
| 255 | Explorer.return_to_parent_value_prompt() |
| 256 | return False |
| 257 | Explorer.explore_expr("*%s" % Explorer.guard_expr(expr), |
| 258 | deref_value, is_child) |
| 259 | return False |
| 260 | |
| 261 | option = raw_input("Continue exploring it as a pointer to an " |
| 262 | "array [y/n]: ") |
| 263 | if option == "y": |
| 264 | while True: |
| 265 | index = 0 |
| 266 | try: |
| 267 | index = int(raw_input("Enter the index of the element you " |
| 268 | "want to explore in '%s': " % expr)) |
| 269 | except ValueError: |
| 270 | break |
| 271 | element_expr = "%s[%d]" % (Explorer.guard_expr(expr), index) |
| 272 | element = value[index] |
| 273 | try: |
| 274 | str(element) |
| 275 | except gdb.MemoryError: |
| 276 | print ("Cannot read value at index %d." % index) |
| 277 | continue |
| 278 | Explorer.explore_expr(element_expr, element, True) |
| 279 | return False |
| 280 | |
| 281 | if is_child: |
| 282 | Explorer.return_to_parent_value() |
| 283 | return False |
| 284 | |
| 285 | @staticmethod |
| 286 | def explore_type(name, datatype, is_child): |
| 287 | """Function to explore pointer types. |
| 288 | See Explorer.explore_type for more information. |
| 289 | """ |
| 290 | target_type = datatype.target() |
| 291 | print ("\n%s is a pointer to a value of type '%s'." % |
| 292 | (name, str(target_type))) |
| 293 | |
| 294 | Explorer.explore_type("the pointee type of %s" % name, |
| 295 | target_type, |
| 296 | is_child) |
| 297 | return False |
| 298 | |
| 299 | |
| 300 | class ReferenceExplorer(object): |
| 301 | """Internal class used to explore reference (TYPE_CODE_REF) values.""" |
| 302 | |
| 303 | @staticmethod |
| 304 | def explore_expr(expr, value, is_child): |
| 305 | """Function to explore array values. |
| 306 | See Explorer.explore_expr for more information. |
| 307 | """ |
| 308 | referenced_value = value.referenced_value() |
| 309 | Explorer.explore_expr(expr, referenced_value, is_child) |
| 310 | return False |
| 311 | |
| 312 | @staticmethod |
| 313 | def explore_type(name, datatype, is_child): |
| 314 | """Function to explore pointer types. |
| 315 | See Explorer.explore_type for more information. |
| 316 | """ |
| 317 | target_type = datatype.target() |
| 318 | Explorer.explore_type(name, target_type, is_child) |
| 319 | return False |
| 320 | |
| 321 | |
| 322 | class ArrayExplorer(object): |
| 323 | """Internal class used to explore arrays.""" |
| 324 | |
| 325 | @staticmethod |
| 326 | def explore_expr(expr, value, is_child): |
| 327 | """Function to explore array values. |
| 328 | See Explorer.explore_expr for more information. |
| 329 | """ |
| 330 | target_type = value.type.target() |
| 331 | print ("'%s' is an array of '%s'." % (expr, str(target_type))) |
| 332 | index = 0 |
| 333 | try: |
| 334 | index = int(raw_input("Enter the index of the element you want to " |
| 335 | "explore in '%s': " % expr)) |
| 336 | except ValueError: |
| 337 | if is_child: |
| 338 | Explorer.return_to_parent_value() |
| 339 | return False |
| 340 | |
| 341 | element = None |
| 342 | try: |
| 343 | element = value[index] |
| 344 | str(element) |
| 345 | except gdb.MemoryError: |
| 346 | print ("Cannot read value at index %d." % index) |
| 347 | raw_input("Press enter to continue... ") |
| 348 | return True |
| 349 | |
| 350 | Explorer.explore_expr("%s[%d]" % (Explorer.guard_expr(expr), index), |
| 351 | element, True) |
| 352 | return True |
| 353 | |
| 354 | @staticmethod |
| 355 | def explore_type(name, datatype, is_child): |
| 356 | """Function to explore array types. |
| 357 | See Explorer.explore_type for more information. |
| 358 | """ |
| 359 | target_type = datatype.target() |
| 360 | print ("%s is an array of '%s'." % (name, str(target_type))) |
| 361 | |
| 362 | Explorer.explore_type("the array element of %s" % name, target_type, |
| 363 | is_child) |
| 364 | return False |
| 365 | |
| 366 | |
| 367 | class CompoundExplorer(object): |
| 368 | """Internal class used to explore struct, classes and unions.""" |
| 369 | |
| 370 | @staticmethod |
| 371 | def _print_fields(print_list): |
| 372 | """Internal function which prints the fields of a struct/class/union. |
| 373 | """ |
| 374 | max_field_name_length = 0 |
| 375 | for pair in print_list: |
| 376 | if max_field_name_length < len(pair[0]): |
| 377 | max_field_name_length = len(pair[0]) |
| 378 | |
| 379 | for pair in print_list: |
| 380 | print (" %*s = %s" % (max_field_name_length, pair[0], pair[1])) |
| 381 | |
| 382 | @staticmethod |
| 383 | def _get_real_field_count(fields): |
| 384 | real_field_count = 0; |
| 385 | for field in fields: |
| 386 | if not field.artificial: |
| 387 | real_field_count = real_field_count + 1 |
| 388 | |
| 389 | return real_field_count |
| 390 | |
| 391 | @staticmethod |
| 392 | def explore_expr(expr, value, is_child): |
| 393 | """Function to explore structs/classes and union values. |
| 394 | See Explorer.explore_expr for more information. |
| 395 | """ |
| 396 | datatype = value.type |
| 397 | type_code = datatype.code |
| 398 | fields = datatype.fields() |
| 399 | |
| 400 | if type_code == gdb.TYPE_CODE_STRUCT: |
| 401 | type_desc = "struct/class" |
| 402 | else: |
| 403 | type_desc = "union" |
| 404 | |
| 405 | if CompoundExplorer._get_real_field_count(fields) == 0: |
| 406 | print ("The value of '%s' is a %s of type '%s' with no fields." % |
| 407 | (expr, type_desc, str(value.type))) |
| 408 | if is_child: |
| 409 | Explorer.return_to_parent_value_prompt() |
| 410 | return False |
| 411 | |
| 412 | print ("The value of '%s' is a %s of type '%s' with the following " |
| 413 | "fields:\n" % (expr, type_desc, str(value.type))) |
| 414 | |
| 415 | has_explorable_fields = False |
| 416 | choice_to_compound_field_map = { } |
| 417 | current_choice = 0 |
| 418 | print_list = [ ] |
| 419 | for field in fields: |
| 420 | if field.artificial: |
| 421 | continue |
| 422 | field_full_name = Explorer.guard_expr(expr) + "." + field.name |
| 423 | if field.is_base_class: |
| 424 | field_value = value.cast(field.type) |
| 425 | else: |
| 426 | field_value = value[field.name] |
| 427 | literal_value = "" |
| 428 | if type_code == gdb.TYPE_CODE_UNION: |
| 429 | literal_value = ("<Enter %d to explore this field of type " |
| 430 | "'%s'>" % (current_choice, str(field.type))) |
| 431 | has_explorable_fields = True |
| 432 | else: |
| 433 | if Explorer.is_scalar_type(field.type): |
| 434 | literal_value = ("%s .. (Value of type '%s')" % |
| 435 | (str(field_value), str(field.type))) |
| 436 | else: |
| 437 | if field.is_base_class: |
| 438 | field_desc = "base class" |
| 439 | else: |
| 440 | field_desc = "field" |
| 441 | literal_value = ("<Enter %d to explore this %s of type " |
| 442 | "'%s'>" % |
| 443 | (current_choice, field_desc, |
| 444 | str(field.type))) |
| 445 | has_explorable_fields = True |
| 446 | |
| 447 | choice_to_compound_field_map[str(current_choice)] = ( |
| 448 | field_full_name, field_value) |
| 449 | current_choice = current_choice + 1 |
| 450 | |
| 451 | print_list.append((field.name, literal_value)) |
| 452 | |
| 453 | CompoundExplorer._print_fields(print_list) |
| 454 | print ("") |
| 455 | |
| 456 | if has_explorable_fields: |
| 457 | choice = raw_input("Enter the field number of choice: ") |
| 458 | if choice in choice_to_compound_field_map: |
| 459 | Explorer.explore_expr(choice_to_compound_field_map[choice][0], |
| 460 | choice_to_compound_field_map[choice][1], |
| 461 | True) |
| 462 | return True |
| 463 | else: |
| 464 | if is_child: |
| 465 | Explorer.return_to_parent_value() |
| 466 | else: |
| 467 | if is_child: |
| 468 | Explorer.return_to_parent_value_prompt() |
| 469 | |
| 470 | return False |
| 471 | |
| 472 | @staticmethod |
| 473 | def explore_type(name, datatype, is_child): |
| 474 | """Function to explore struct/class and union types. |
| 475 | See Explorer.explore_type for more information. |
| 476 | """ |
| 477 | type_code = datatype.code |
| 478 | type_desc = "" |
| 479 | if type_code == gdb.TYPE_CODE_STRUCT: |
| 480 | type_desc = "struct/class" |
| 481 | else: |
| 482 | type_desc = "union" |
| 483 | |
| 484 | fields = datatype.fields() |
| 485 | if CompoundExplorer._get_real_field_count(fields) == 0: |
| 486 | if is_child: |
| 487 | print ("%s is a %s of type '%s' with no fields." % |
| 488 | (name, type_desc, str(datatype))) |
| 489 | Explorer.return_to_enclosing_type_prompt() |
| 490 | else: |
| 491 | print ("'%s' is a %s with no fields." % (name, type_desc)) |
| 492 | return False |
| 493 | |
| 494 | if is_child: |
| 495 | print ("%s is a %s of type '%s' " |
| 496 | "with the following fields:\n" % |
| 497 | (name, type_desc, str(datatype))) |
| 498 | else: |
| 499 | print ("'%s' is a %s with the following " |
| 500 | "fields:\n" % |
| 501 | (name, type_desc)) |
| 502 | |
| 503 | has_explorable_fields = False |
| 504 | current_choice = 0 |
| 505 | choice_to_compound_field_map = { } |
| 506 | print_list = [ ] |
| 507 | for field in fields: |
| 508 | if field.artificial: |
| 509 | continue |
| 510 | if field.is_base_class: |
| 511 | field_desc = "base class" |
| 512 | else: |
| 513 | field_desc = "field" |
| 514 | rhs = ("<Enter %d to explore this %s of type '%s'>" % |
| 515 | (current_choice, field_desc, str(field.type))) |
| 516 | print_list.append((field.name, rhs)) |
| 517 | choice_to_compound_field_map[str(current_choice)] = ( |
| 518 | field.name, field.type, field_desc) |
| 519 | current_choice = current_choice + 1 |
| 520 | |
| 521 | CompoundExplorer._print_fields(print_list) |
| 522 | print ("") |
| 523 | |
| 524 | if len(choice_to_compound_field_map) > 0: |
| 525 | choice = raw_input("Enter the field number of choice: ") |
| 526 | if choice in choice_to_compound_field_map: |
| 527 | if is_child: |
| 528 | new_name = ("%s '%s' of %s" % |
| 529 | (choice_to_compound_field_map[choice][2], |
| 530 | choice_to_compound_field_map[choice][0], |
| 531 | name)) |
| 532 | else: |
| 533 | new_name = ("%s '%s' of '%s'" % |
| 534 | (choice_to_compound_field_map[choice][2], |
| 535 | choice_to_compound_field_map[choice][0], |
| 536 | name)) |
| 537 | Explorer.explore_type(new_name, |
| 538 | choice_to_compound_field_map[choice][1], True) |
| 539 | return True |
| 540 | else: |
| 541 | if is_child: |
| 542 | Explorer.return_to_enclosing_type() |
| 543 | else: |
| 544 | if is_child: |
| 545 | Explorer.return_to_enclosing_type_prompt() |
| 546 | |
| 547 | return False |
| 548 | |
| 549 | |
| 550 | class TypedefExplorer(object): |
| 551 | """Internal class used to explore values whose type is a typedef.""" |
| 552 | |
| 553 | @staticmethod |
| 554 | def explore_expr(expr, value, is_child): |
| 555 | """Function to explore typedef values. |
| 556 | See Explorer.explore_expr for more information. |
| 557 | """ |
| 558 | actual_type = value.type.strip_typedefs() |
| 559 | print ("The value of '%s' is of type '%s' " |
| 560 | "which is a typedef of type '%s'" % |
| 561 | (expr, str(value.type), str(actual_type))) |
| 562 | |
| 563 | Explorer.explore_expr(expr, value.cast(actual_type), is_child) |
| 564 | return False |
| 565 | |
| 566 | @staticmethod |
| 567 | def explore_type(name, datatype, is_child): |
| 568 | """Function to explore typedef types. |
| 569 | See Explorer.explore_type for more information. |
| 570 | """ |
| 571 | actual_type = datatype.strip_typedefs() |
| 572 | if is_child: |
| 573 | print ("The type of %s is a typedef of type '%s'." % |
| 574 | (name, str(actual_type))) |
| 575 | else: |
| 576 | print ("The type '%s' is a typedef of type '%s'." % |
| 577 | (name, str(actual_type))) |
| 578 | |
| 579 | Explorer.explore_type(name, actual_type, is_child) |
| 580 | return False |
| 581 | |
| 582 | |
| 583 | class ExploreUtils(object): |
| 584 | """Internal class which provides utilities for the main command classes.""" |
| 585 | |
| 586 | @staticmethod |
| 587 | def check_args(name, arg_str): |
| 588 | """Utility to check if adequate number of arguments are passed to an |
| 589 | explore command. |
| 590 | |
| 591 | Arguments: |
| 592 | name: The name of the explore command. |
| 593 | arg_str: The argument string passed to the explore command. |
| 594 | |
| 595 | Returns: |
| 596 | True if adequate arguments are passed, false otherwise. |
| 597 | |
| 598 | Raises: |
| 599 | gdb.GdbError if adequate arguments are not passed. |
| 600 | """ |
| 601 | if len(arg_str) < 1: |
| 602 | raise gdb.GdbError("ERROR: '%s' requires an argument." |
| 603 | % name) |
| 604 | return False |
| 605 | else: |
| 606 | return True |
| 607 | |
| 608 | @staticmethod |
| 609 | def get_type_from_str(type_str): |
| 610 | """A utility function to deduce the gdb.Type value from a string |
| 611 | representing the type. |
| 612 | |
| 613 | Arguments: |
| 614 | type_str: The type string from which the gdb.Type value should be |
| 615 | deduced. |
| 616 | |
| 617 | Returns: |
| 618 | The deduced gdb.Type value if possible, None otherwise. |
| 619 | """ |
| 620 | try: |
| 621 | # Assume the current language to be C/C++ and make a try. |
| 622 | return gdb.parse_and_eval("(%s *)0" % type_str).type.target() |
| 623 | except RuntimeError: |
| 624 | # If assumption of current language to be C/C++ was wrong, then |
| 625 | # lookup the type using the API. |
| 626 | try: |
| 627 | return gdb.lookup_type(type_str) |
| 628 | except RuntimeError: |
| 629 | return None |
| 630 | |
| 631 | @staticmethod |
| 632 | def get_value_from_str(value_str): |
| 633 | """A utility function to deduce the gdb.Value value from a string |
| 634 | representing the value. |
| 635 | |
| 636 | Arguments: |
| 637 | value_str: The value string from which the gdb.Value value should |
| 638 | be deduced. |
| 639 | |
| 640 | Returns: |
| 641 | The deduced gdb.Value value if possible, None otherwise. |
| 642 | """ |
| 643 | try: |
| 644 | return gdb.parse_and_eval(value_str) |
| 645 | except RuntimeError: |
| 646 | return None |
| 647 | |
| 648 | |
| 649 | class ExploreCommand(gdb.Command): |
| 650 | """Explore a value or a type valid in the current context. |
| 651 | |
| 652 | Usage: |
| 653 | |
| 654 | explore ARG |
| 655 | |
| 656 | - ARG is either a valid expression or a type name. |
| 657 | - At any stage of exploration, hit the return key (instead of a |
| 658 | choice, if any) to return to the enclosing type or value. |
| 659 | """ |
| 660 | |
| 661 | def __init__(self): |
| 662 | super(ExploreCommand, self).__init__(name = "explore", |
| 663 | command_class = gdb.COMMAND_DATA, |
| 664 | prefix = True) |
| 665 | |
| 666 | def invoke(self, arg_str, from_tty): |
| 667 | if ExploreUtils.check_args("explore", arg_str) == False: |
| 668 | return |
| 669 | |
| 670 | # Check if it is a value |
| 671 | value = ExploreUtils.get_value_from_str(arg_str) |
| 672 | if value is not None: |
| 673 | Explorer.explore_expr(arg_str, value, False) |
| 674 | return |
| 675 | |
| 676 | # If it is not a value, check if it is a type |
| 677 | datatype = ExploreUtils.get_type_from_str(arg_str) |
| 678 | if datatype is not None: |
| 679 | Explorer.explore_type(arg_str, datatype, False) |
| 680 | return |
| 681 | |
| 682 | # If it is neither a value nor a type, raise an error. |
| 683 | raise gdb.GdbError( |
| 684 | ("'%s' neither evaluates to a value nor is a type " |
| 685 | "in the current context." % |
| 686 | arg_str)) |
| 687 | |
| 688 | |
| 689 | class ExploreValueCommand(gdb.Command): |
| 690 | """Explore value of an expression valid in the current context. |
| 691 | |
| 692 | Usage: |
| 693 | |
| 694 | explore value ARG |
| 695 | |
| 696 | - ARG is a valid expression. |
| 697 | - At any stage of exploration, hit the return key (instead of a |
| 698 | choice, if any) to return to the enclosing value. |
| 699 | """ |
| 700 | |
| 701 | def __init__(self): |
| 702 | super(ExploreValueCommand, self).__init__( |
| 703 | name = "explore value", command_class = gdb.COMMAND_DATA) |
| 704 | |
| 705 | def invoke(self, arg_str, from_tty): |
| 706 | if ExploreUtils.check_args("explore value", arg_str) == False: |
| 707 | return |
| 708 | |
| 709 | value = ExploreUtils.get_value_from_str(arg_str) |
| 710 | if value is None: |
| 711 | raise gdb.GdbError( |
| 712 | (" '%s' does not evaluate to a value in the current " |
| 713 | "context." % |
| 714 | arg_str)) |
| 715 | return |
| 716 | |
| 717 | Explorer.explore_expr(arg_str, value, False) |
| 718 | |
| 719 | |
| 720 | class ExploreTypeCommand(gdb.Command): |
| 721 | """Explore a type or the type of an expression valid in the current |
| 722 | context. |
| 723 | |
| 724 | Usage: |
| 725 | |
| 726 | explore type ARG |
| 727 | |
| 728 | - ARG is a valid expression or a type name. |
| 729 | - At any stage of exploration, hit the return key (instead of a |
| 730 | choice, if any) to return to the enclosing type. |
| 731 | """ |
| 732 | |
| 733 | def __init__(self): |
| 734 | super(ExploreTypeCommand, self).__init__( |
| 735 | name = "explore type", command_class = gdb.COMMAND_DATA) |
| 736 | |
| 737 | def invoke(self, arg_str, from_tty): |
| 738 | if ExploreUtils.check_args("explore type", arg_str) == False: |
| 739 | return |
| 740 | |
| 741 | datatype = ExploreUtils.get_type_from_str(arg_str) |
| 742 | if datatype is not None: |
| 743 | Explorer.explore_type(arg_str, datatype, False) |
| 744 | return |
| 745 | |
| 746 | value = ExploreUtils.get_value_from_str(arg_str) |
| 747 | if value is not None: |
| 748 | print ("'%s' is of type '%s'." % (arg_str, str(value.type))) |
| 749 | Explorer.explore_type(str(value.type), value.type, False) |
| 750 | return |
| 751 | |
| 752 | raise gdb.GdbError(("'%s' is not a type or value in the current " |
| 753 | "context." % arg_str)) |
| 754 | |
| 755 | |
| 756 | Explorer.init_env() |
| 757 | |
| 758 | ExploreCommand() |
| 759 | ExploreValueCommand() |
| 760 | ExploreTypeCommand() |