Index: gdb/python/lib/gdb/command/explore.py |
diff --git a/gdb/python/lib/gdb/command/explore.py b/gdb/python/lib/gdb/command/explore.py |
new file mode 100644 |
index 0000000000000000000000000000000000000000..aad36717f8fb72469921709aafd18db23994bd51 |
--- /dev/null |
+++ b/gdb/python/lib/gdb/command/explore.py |
@@ -0,0 +1,755 @@ |
+# GDB 'explore' command. |
+# Copyright (C) 2012 Free Software Foundation, Inc. |
+ |
+# This program is free software; you can redistribute it and/or modify |
+# it under the terms of the GNU General Public License as published by |
+# the Free Software Foundation; either version 3 of the License, or |
+# (at your option) any later version. |
+# |
+# This program is distributed in the hope that it will be useful, |
+# but WITHOUT ANY WARRANTY; without even the implied warranty of |
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
+# GNU General Public License for more details. |
+# |
+# You should have received a copy of the GNU General Public License |
+# along with this program. If not, see <http://www.gnu.org/licenses/>. |
+ |
+"""Implementation of the GDB 'explore' command using the GDB Python API.""" |
+ |
+import gdb |
+ |
+class Explorer(object): |
+ """Internal class which invokes other explorers.""" |
+ |
+ # This map is filled by the Explorer.init_env() function |
+ type_code_to_explorer_map = { } |
+ |
+ _SCALAR_TYPE_LIST = ( |
+ gdb.TYPE_CODE_CHAR, |
+ gdb.TYPE_CODE_INT, |
+ gdb.TYPE_CODE_BOOL, |
+ gdb.TYPE_CODE_FLT, |
+ gdb.TYPE_CODE_VOID, |
+ gdb.TYPE_CODE_ENUM, |
+ ) |
+ |
+ @staticmethod |
+ def guard_expr(expr): |
+ length = len(expr) |
+ guard = False |
+ |
+ if expr[0] == '(' and expr[length-1] == ')': |
+ pass |
+ else: |
+ i = 0 |
+ while i < length: |
+ c = expr[i] |
+ if (c == '_' or ('a' <= c and c <= 'z') or |
+ ('A' <= c and c <= 'Z') or ('0' <= c and c <= '9')): |
+ pass |
+ else: |
+ guard = True |
+ break |
+ i += 1 |
+ |
+ if guard: |
+ return "(" + expr + ")" |
+ else: |
+ return expr |
+ |
+ @staticmethod |
+ def explore_expr(expr, value, is_child): |
+ """Main function to explore an expression value. |
+ |
+ Arguments: |
+ expr: The expression string that is being explored. |
+ value: The gdb.Value value of the expression. |
+ is_child: Boolean value to indicate if the expression is a child. |
+ An expression is a child if it is derived from the main |
+ expression entered by the user. For example, if the user |
+ entered an expression which evaluates to a struct, then |
+ when exploring the fields of the struct, is_child is set |
+ to True internally. |
+ |
+ Returns: |
+ No return value. |
+ """ |
+ type_code = value.type.code |
+ if type_code in Explorer.type_code_to_explorer_map: |
+ explorer_class = Explorer.type_code_to_explorer_map[type_code] |
+ while explorer_class.explore_expr(expr, value, is_child): |
+ pass |
+ else: |
+ print ("Explorer for type '%s' not yet available.\n" % |
+ str(value.type)) |
+ |
+ @staticmethod |
+ def explore_type(name, datatype, is_child): |
+ """Main function to explore a data type. |
+ |
+ Arguments: |
+ name: The string representing the path to the data type being |
+ explored. |
+ datatype: The gdb.Type value of the data type being explored. |
+ is_child: Boolean value to indicate if the name is a child. |
+ A name is a child if it is derived from the main name |
+ entered by the user. For example, if the user entered |
+ the name of struct type, then when exploring the fields |
+ of the struct, is_child is set to True internally. |
+ |
+ Returns: |
+ No return value. |
+ """ |
+ type_code = datatype.code |
+ if type_code in Explorer.type_code_to_explorer_map: |
+ explorer_class = Explorer.type_code_to_explorer_map[type_code] |
+ while explorer_class.explore_type(name, datatype, is_child): |
+ pass |
+ else: |
+ print ("Explorer for type '%s' not yet available.\n" % |
+ str(datatype)) |
+ |
+ @staticmethod |
+ def init_env(): |
+ """Initializes the Explorer environment. |
+ This function should be invoked before starting any exploration. If |
+ invoked before an exploration, it need not be invoked for subsequent |
+ explorations. |
+ """ |
+ Explorer.type_code_to_explorer_map = { |
+ gdb.TYPE_CODE_CHAR : ScalarExplorer, |
+ gdb.TYPE_CODE_INT : ScalarExplorer, |
+ gdb.TYPE_CODE_BOOL : ScalarExplorer, |
+ gdb.TYPE_CODE_FLT : ScalarExplorer, |
+ gdb.TYPE_CODE_VOID : ScalarExplorer, |
+ gdb.TYPE_CODE_ENUM : ScalarExplorer, |
+ gdb.TYPE_CODE_STRUCT : CompoundExplorer, |
+ gdb.TYPE_CODE_UNION : CompoundExplorer, |
+ gdb.TYPE_CODE_PTR : PointerExplorer, |
+ gdb.TYPE_CODE_REF : ReferenceExplorer, |
+ gdb.TYPE_CODE_TYPEDEF : TypedefExplorer, |
+ gdb.TYPE_CODE_ARRAY : ArrayExplorer |
+ } |
+ |
+ @staticmethod |
+ def is_scalar_type(type): |
+ """Checks whether a type is a scalar type. |
+ A type is a scalar type of its type is |
+ gdb.TYPE_CODE_CHAR or |
+ gdb.TYPE_CODE_INT or |
+ gdb.TYPE_CODE_BOOL or |
+ gdb.TYPE_CODE_FLT or |
+ gdb.TYPE_CODE_VOID or |
+ gdb.TYPE_CODE_ENUM. |
+ |
+ Arguments: |
+ type: The type to be checked. |
+ |
+ Returns: |
+ 'True' if 'type' is a scalar type. 'False' otherwise. |
+ """ |
+ return type.code in Explorer._SCALAR_TYPE_LIST |
+ |
+ @staticmethod |
+ def return_to_parent_value(): |
+ """A utility function which prints that the current exploration session |
+ is returning to the parent value. Useful when exploring values. |
+ """ |
+ print "\nReturning to parent value...\n" |
+ |
+ @staticmethod |
+ def return_to_parent_value_prompt(): |
+ """A utility function which prompts the user to press the 'enter' key |
+ so that the exploration session can shift back to the parent value. |
+ Useful when exploring values. |
+ """ |
+ raw_input("\nPress enter to return to parent value: ") |
+ |
+ @staticmethod |
+ def return_to_enclosing_type(): |
+ """A utility function which prints that the current exploration session |
+ is returning to the enclosing type. Useful when exploring types. |
+ """ |
+ print "\nReturning to enclosing type...\n" |
+ |
+ @staticmethod |
+ def return_to_enclosing_type_prompt(): |
+ """A utility function which prompts the user to press the 'enter' key |
+ so that the exploration session can shift back to the enclosing type. |
+ Useful when exploring types. |
+ """ |
+ raw_input("\nPress enter to return to enclosing type: ") |
+ |
+ |
+class ScalarExplorer(object): |
+ """Internal class used to explore scalar values.""" |
+ |
+ @staticmethod |
+ def explore_expr(expr, value, is_child): |
+ """Function to explore scalar values. |
+ See Explorer.explore_expr and Explorer.is_scalar_type for more |
+ information. |
+ """ |
+ print ("'%s' is a scalar value of type '%s'." % |
+ (expr, value.type)) |
+ print "%s = %s" % (expr, str(value)) |
+ |
+ if is_child: |
+ Explorer.return_to_parent_value_prompt() |
+ Explorer.return_to_parent_value() |
+ |
+ return False |
+ |
+ @staticmethod |
+ def explore_type(name, datatype, is_child): |
+ """Function to explore scalar types. |
+ See Explorer.explore_type and Explorer.is_scalar_type for more |
+ information. |
+ """ |
+ if datatype.code == gdb.TYPE_CODE_ENUM: |
+ if is_child: |
+ print ("%s is of an enumerated type '%s'." % |
+ (name, str(datatype))) |
+ else: |
+ print "'%s' is an enumerated type." % name |
+ else: |
+ if is_child: |
+ print ("%s is of a scalar type '%s'." % |
+ (name, str(datatype))) |
+ else: |
+ print "'%s' is a scalar type." % name |
+ |
+ if is_child: |
+ Explorer.return_to_enclosing_type_prompt() |
+ Explorer.return_to_enclosing_type() |
+ |
+ return False |
+ |
+ |
+class PointerExplorer(object): |
+ """Internal class used to explore pointer values.""" |
+ |
+ @staticmethod |
+ def explore_expr(expr, value, is_child): |
+ """Function to explore pointer values. |
+ See Explorer.explore_expr for more information. |
+ """ |
+ print ("'%s' is a pointer to a value of type '%s'" % |
+ (expr, str(value.type.target()))) |
+ option = raw_input("Continue exploring it as a pointer to a single " |
+ "value [y/n]: ") |
+ if option == "y": |
+ deref_value = None |
+ try: |
+ deref_value = value.dereference() |
+ str(deref_value) |
+ except gdb.MemoryError: |
+ print ("'%s' a pointer pointing to an invalid memory " |
+ "location." % expr) |
+ if is_child: |
+ Explorer.return_to_parent_value_prompt() |
+ return False |
+ Explorer.explore_expr("*%s" % Explorer.guard_expr(expr), |
+ deref_value, is_child) |
+ return False |
+ |
+ option = raw_input("Continue exploring it as a pointer to an " |
+ "array [y/n]: ") |
+ if option == "y": |
+ while True: |
+ index = 0 |
+ try: |
+ index = int(raw_input("Enter the index of the element you " |
+ "want to explore in '%s': " % expr)) |
+ except ValueError: |
+ break |
+ element_expr = "%s[%d]" % (Explorer.guard_expr(expr), index) |
+ element = value[index] |
+ try: |
+ str(element) |
+ except gdb.MemoryError: |
+ print "Cannot read value at index %d." % index |
+ continue |
+ Explorer.explore_expr(element_expr, element, True) |
+ return False |
+ |
+ if is_child: |
+ Explorer.return_to_parent_value() |
+ return False |
+ |
+ @staticmethod |
+ def explore_type(name, datatype, is_child): |
+ """Function to explore pointer types. |
+ See Explorer.explore_type for more information. |
+ """ |
+ target_type = datatype.target() |
+ print ("\n%s is a pointer to a value of type '%s'." % |
+ (name, str(target_type))) |
+ |
+ Explorer.explore_type("the pointee type of %s" % name, |
+ target_type, |
+ is_child) |
+ return False |
+ |
+ |
+class ReferenceExplorer(object): |
+ """Internal class used to explore reference (TYPE_CODE_REF) values.""" |
+ |
+ @staticmethod |
+ def explore_expr(expr, value, is_child): |
+ """Function to explore array values. |
+ See Explorer.explore_expr for more information. |
+ """ |
+ referenced_value = value.referenced_value() |
+ Explorer.explore_expr(expr, referenced_value, is_child) |
+ return False |
+ |
+ @staticmethod |
+ def explore_type(name, datatype, is_child): |
+ """Function to explore pointer types. |
+ See Explorer.explore_type for more information. |
+ """ |
+ target_type = datatype.target() |
+ Explorer.explore_type(name, target_type, is_child) |
+ return False |
+ |
+ |
+class ArrayExplorer(object): |
+ """Internal class used to explore arrays.""" |
+ |
+ @staticmethod |
+ def explore_expr(expr, value, is_child): |
+ """Function to explore array values. |
+ See Explorer.explore_expr for more information. |
+ """ |
+ target_type = value.type.target() |
+ print ("'%s' is an array of '%s'." % (expr, str(target_type))) |
+ index = 0 |
+ try: |
+ index = int(raw_input("Enter the index of the element you want to " |
+ "explore in '%s': " % expr)) |
+ except ValueError: |
+ if is_child: |
+ Explorer.return_to_parent_value() |
+ return False |
+ |
+ element = None |
+ try: |
+ element = value[index] |
+ str(element) |
+ except gdb.MemoryError: |
+ print "Cannot read value at index %d." % index |
+ raw_input("Press enter to continue... ") |
+ return True |
+ |
+ Explorer.explore_expr("%s[%d]" % (Explorer.guard_expr(expr), index), |
+ element, True) |
+ return True |
+ |
+ @staticmethod |
+ def explore_type(name, datatype, is_child): |
+ """Function to explore array types. |
+ See Explorer.explore_type for more information. |
+ """ |
+ target_type = datatype.target() |
+ print "%s is an array of '%s'." % (name, str(target_type)) |
+ |
+ Explorer.explore_type("the array element of %s" % name, target_type, |
+ is_child) |
+ return False |
+ |
+ |
+class CompoundExplorer(object): |
+ """Internal class used to explore struct, classes and unions.""" |
+ |
+ @staticmethod |
+ def _print_fields(print_list): |
+ """Internal function which prints the fields of a struct/class/union. |
+ """ |
+ max_field_name_length = 0 |
+ for pair in print_list: |
+ if max_field_name_length < len(pair[0]): |
+ max_field_name_length = len(pair[0]) |
+ |
+ format_str = " {0:>%d} = {1}" % max_field_name_length |
+ for pair in print_list: |
+ print format_str.format(pair[0], pair[1]) |
+ |
+ @staticmethod |
+ def _get_real_field_count(fields): |
+ real_field_count = 0; |
+ for field in fields: |
+ if not field.artificial: |
+ real_field_count = real_field_count + 1 |
+ |
+ return real_field_count |
+ |
+ @staticmethod |
+ def explore_expr(expr, value, is_child): |
+ """Function to explore structs/classes and union values. |
+ See Explorer.explore_expr for more information. |
+ """ |
+ datatype = value.type |
+ type_code = datatype.code |
+ fields = datatype.fields() |
+ |
+ if type_code == gdb.TYPE_CODE_STRUCT: |
+ type_desc = "struct/class" |
+ else: |
+ type_desc = "union" |
+ |
+ if CompoundExplorer._get_real_field_count(fields) == 0: |
+ print ("The value of '%s' is a %s of type '%s' with no fields." % |
+ (expr, type_desc, str(value.type))) |
+ if is_child: |
+ Explorer.return_to_parent_value_prompt() |
+ return False |
+ |
+ print ("The value of '%s' is a %s of type '%s' with the following " |
+ "fields:\n" % (expr, type_desc, str(value.type))) |
+ |
+ has_explorable_fields = False |
+ choice_to_compound_field_map = { } |
+ current_choice = 0 |
+ print_list = [ ] |
+ for field in fields: |
+ if field.artificial: |
+ continue |
+ field_full_name = Explorer.guard_expr(expr) + "." + field.name |
+ if field.is_base_class: |
+ field_value = value.cast(field.type) |
+ else: |
+ field_value = value[field.name] |
+ literal_value = "" |
+ if type_code == gdb.TYPE_CODE_UNION: |
+ literal_value = ("<Enter %d to explore this field of type " |
+ "'%s'>" % (current_choice, str(field.type))) |
+ has_explorable_fields = True |
+ else: |
+ if Explorer.is_scalar_type(field.type): |
+ literal_value = ("%s .. (Value of type '%s')" % |
+ (str(field_value), str(field.type))) |
+ else: |
+ if field.is_base_class: |
+ field_desc = "base class" |
+ else: |
+ field_desc = "field" |
+ literal_value = ("<Enter %d to explore this %s of type " |
+ "'%s'>" % |
+ (current_choice, field_desc, |
+ str(field.type))) |
+ has_explorable_fields = True |
+ |
+ choice_to_compound_field_map[str(current_choice)] = ( |
+ field_full_name, field_value) |
+ current_choice = current_choice + 1 |
+ |
+ print_list.append((field.name, literal_value)) |
+ |
+ CompoundExplorer._print_fields(print_list) |
+ print "" |
+ |
+ if has_explorable_fields: |
+ choice = raw_input("Enter the field number of choice: ") |
+ if choice in choice_to_compound_field_map: |
+ Explorer.explore_expr(choice_to_compound_field_map[choice][0], |
+ choice_to_compound_field_map[choice][1], |
+ True) |
+ return True |
+ else: |
+ if is_child: |
+ Explorer.returning_to_parent_value_message() |
+ else: |
+ if is_child: |
+ Explorer.return_to_parent_value_prompt() |
+ |
+ return False |
+ |
+ @staticmethod |
+ def explore_type(name, datatype, is_child): |
+ """Function to explore struct/class and union types. |
+ See Explorer.explore_type for more information. |
+ """ |
+ type_code = datatype.code |
+ type_desc = "" |
+ if type_code == gdb.TYPE_CODE_STRUCT: |
+ type_desc = "struct/class" |
+ else: |
+ type_desc = "union" |
+ |
+ fields = datatype.fields() |
+ if CompoundExplorer._get_real_field_count(fields) == 0: |
+ if is_child: |
+ print ("%s is a %s of type '%s' with no fields." % |
+ (name, type_desc, str(datatype))) |
+ Explorer.return_to_enclosing_type_prompt() |
+ else: |
+ print "'%s' is a %s with no fields." % (name, type_desc) |
+ return False |
+ |
+ if is_child: |
+ print ("%s is a %s of type '%s' " |
+ "with the following fields:\n" % |
+ (name, type_desc, str(datatype))) |
+ else: |
+ print ("'%s' is a %s with the following " |
+ "fields:\n" % |
+ (name, type_desc)) |
+ |
+ has_explorable_fields = False |
+ current_choice = 0 |
+ choice_to_compound_field_map = { } |
+ print_list = [ ] |
+ for field in fields: |
+ if field.artificial: |
+ continue |
+ if field.is_base_class: |
+ field_desc = "base class" |
+ else: |
+ field_desc = "field" |
+ rhs = ("<Enter %d to explore this %s of type '%s'>" % |
+ (current_choice, field_desc, str(field.type))) |
+ print_list.append((field.name, rhs)) |
+ choice_to_compound_field_map[str(current_choice)] = ( |
+ field.name, field.type, field_desc) |
+ current_choice = current_choice + 1 |
+ |
+ CompoundExplorer._print_fields(print_list) |
+ print "" |
+ |
+ if len(choice_to_compound_field_map) > 0: |
+ choice = raw_input("Enter the field number of choice: ") |
+ if choice in choice_to_compound_field_map: |
+ if is_child: |
+ new_name = ("%s '%s' of %s" % |
+ (choice_to_compound_field_map[choice][2], |
+ choice_to_compound_field_map[choice][0], |
+ name)) |
+ else: |
+ new_name = ("%s '%s' of '%s'" % |
+ (choice_to_compound_field_map[choice][2], |
+ choice_to_compound_field_map[choice][0], |
+ name)) |
+ Explorer.explore_type(new_name, |
+ choice_to_compound_field_map[choice][1], True) |
+ return True |
+ else: |
+ if is_child: |
+ Explorer.return_to_enclosing_type() |
+ else: |
+ if is_child: |
+ Explorer.return_to_enclosing_type_prompt() |
+ |
+ return False |
+ |
+ |
+class TypedefExplorer(object): |
+ """Internal class used to explore values whose type is a typedef.""" |
+ |
+ @staticmethod |
+ def explore_expr(expr, value, is_child): |
+ """Function to explore typedef values. |
+ See Explorer.explore_expr for more information. |
+ """ |
+ actual_type = value.type.strip_typedefs() |
+ print ("The value of '%s' is of type '%s' " |
+ "which is a typedef of type '%s'" % |
+ (expr, str(value.type), str(actual_type))) |
+ |
+ Explorer.explore_expr(expr, value.cast(actual_type), is_child) |
+ return False |
+ |
+ @staticmethod |
+ def explore_type(name, datatype, is_child): |
+ """Function to explore typedef types. |
+ See Explorer.explore_type for more information. |
+ """ |
+ actual_type = datatype.strip_typedefs() |
+ if is_child: |
+ print ("The type of %s is a typedef of type '%s'." % |
+ (name, str(actual_type))) |
+ else: |
+ print ("The type '%s' is a typedef of type '%s'." % |
+ (name, str(actual_type))) |
+ |
+ Explorer.explore_type(name, actual_type, is_child) |
+ return False |
+ |
+ |
+class ExploreUtils(object): |
+ """Internal class which provides utilities for the main command classes.""" |
+ |
+ @staticmethod |
+ def check_args(name, arg_str): |
+ """Utility to check if adequate number of arguments are passed to an |
+ explore command. |
+ |
+ Arguments: |
+ name: The name of the explore command. |
+ arg_str: The argument string passed to the explore command. |
+ |
+ Returns: |
+ True if adequate arguments are passed, false otherwise. |
+ |
+ Raises: |
+ gdb.GdbError if adequate arguments are not passed. |
+ """ |
+ if len(arg_str) < 1: |
+ raise gdb.GdbError("ERROR: '%s' requires an argument." |
+ % name) |
+ return False |
+ else: |
+ return True |
+ |
+ @staticmethod |
+ def get_type_from_str(type_str): |
+ """A utility function to deduce the gdb.Type value from a string |
+ representing the type. |
+ |
+ Arguments: |
+ type_str: The type string from which the gdb.Type value should be |
+ deduced. |
+ |
+ Returns: |
+ The deduced gdb.Type value if possible, None otherwise. |
+ """ |
+ try: |
+ # Assume the current language to be C/C++ and make a try. |
+ return gdb.parse_and_eval("(%s *)0" % type_str).type.target() |
+ except RuntimeError: |
+ # If assumption of current language to be C/C++ was wrong, then |
+ # lookup the type using the API. |
+ try: |
+ return gdb.lookup_type(type_str) |
+ except RuntimeError: |
+ return None |
+ |
+ @staticmethod |
+ def get_value_from_str(value_str): |
+ """A utility function to deduce the gdb.Value value from a string |
+ representing the value. |
+ |
+ Arguments: |
+ value_str: The value string from which the gdb.Value value should |
+ be deduced. |
+ |
+ Returns: |
+ The deduced gdb.Value value if possible, None otherwise. |
+ """ |
+ try: |
+ return gdb.parse_and_eval(value_str) |
+ except RuntimeError: |
+ return None |
+ |
+ |
+class ExploreCommand(gdb.Command): |
+ """Explore a value or a type valid in the current context. |
+ |
+ Usage: |
+ |
+ explore ARG |
+ |
+ - ARG is either a valid expression or a type name. |
+ - At any stage of exploration, hit the return key (instead of a |
+ choice, if any) to return to the enclosing type or value. |
+ """ |
+ |
+ def __init__(self): |
+ super(ExploreCommand, self).__init__(name = "explore", |
+ command_class = gdb.COMMAND_DATA, |
+ prefix = True) |
+ |
+ def invoke(self, arg_str, from_tty): |
+ if ExploreUtils.check_args("explore", arg_str) == False: |
+ return |
+ |
+ # Check if it is a value |
+ value = ExploreUtils.get_value_from_str(arg_str) |
+ if value is not None: |
+ Explorer.explore_expr(arg_str, value, False) |
+ return |
+ |
+ # If it is not a value, check if it is a type |
+ datatype = ExploreUtils.get_type_from_str(arg_str) |
+ if datatype is not None: |
+ Explorer.explore_type(arg_str, datatype, False) |
+ return |
+ |
+ # If it is neither a value nor a type, raise an error. |
+ raise gdb.GdbError( |
+ ("'%s' neither evaluates to a value nor is a type " |
+ "in the current context." % |
+ arg_str)) |
+ |
+ |
+class ExploreValueCommand(gdb.Command): |
+ """Explore value of an expression valid in the current context. |
+ |
+ Usage: |
+ |
+ explore value ARG |
+ |
+ - ARG is a valid expression. |
+ - At any stage of exploration, hit the return key (instead of a |
+ choice, if any) to return to the enclosing value. |
+ """ |
+ |
+ def __init__(self): |
+ super(ExploreValueCommand, self).__init__( |
+ name = "explore value", command_class = gdb.COMMAND_DATA) |
+ |
+ def invoke(self, arg_str, from_tty): |
+ if ExploreUtils.check_args("explore value", arg_str) == False: |
+ return |
+ |
+ value = ExploreUtils.get_value_from_str(arg_str) |
+ if value is None: |
+ raise gdb.GdbError( |
+ (" '%s' does not evaluate to a value in the current " |
+ "context." % |
+ arg_str)) |
+ return |
+ |
+ Explorer.explore_expr(arg_str, value, False) |
+ |
+ |
+class ExploreTypeCommand(gdb.Command): |
+ """Explore a type or the type of an expression valid in the current |
+ context. |
+ |
+ Usage: |
+ |
+ explore type ARG |
+ |
+ - ARG is a valid expression or a type name. |
+ - At any stage of exploration, hit the return key (instead of a |
+ choice, if any) to return to the enclosing type. |
+ """ |
+ |
+ def __init__(self): |
+ super(ExploreTypeCommand, self).__init__( |
+ name = "explore type", command_class = gdb.COMMAND_DATA) |
+ |
+ def invoke(self, arg_str, from_tty): |
+ if ExploreUtils.check_args("explore type", arg_str) == False: |
+ return |
+ |
+ datatype = ExploreUtils.get_type_from_str(arg_str) |
+ if datatype is not None: |
+ Explorer.explore_type(arg_str, datatype, False) |
+ return |
+ |
+ value = ExploreUtils.get_value_from_str(arg_str) |
+ if value is not None: |
+ print "'%s' is of type '%s'." % (arg_str, str(value.type)) |
+ Explorer.explore_type(str(value.type), value.type, False) |
+ |
+ raise gdb.GdbError(("'%s' is not a type or value in the current " |
+ "context." % arg_str)) |
+ |
+ |
+Explorer.init_env() |
+ |
+ExploreCommand() |
+ExploreValueCommand() |
+ExploreTypeCommand() |