blah
authorJorge Gorbe <j.gorbe@stcsl.es>
Wed, 24 Oct 2012 13:00:07 +0000 (15:00 +0200)
committerJorge Gorbe <j.gorbe@stcsl.es>
Wed, 24 Oct 2012 13:00:07 +0000 (15:00 +0200)
index.html
samples/explore.py [new file with mode: 0644]
samples/plist.gdb [new file with mode: 0644]
samples/script.py [new file with mode: 0644]
samples/test2.c

index 17b8b450339f9573b3675a046728609ec786b6b5..c7761aead22aa5a8875e9fe9dc5744324045ba50 100644 (file)
@@ -97,7 +97,7 @@ End with a line saying just "end".
 </section>
 
 <section class="slide">
-       <h2> Custom commands </h2>
+       <h2> Custom commands (1/2) </h2>
 <pre>
 (gdb) define plist
 Type commands for definition of "plist".
@@ -111,6 +111,26 @@ End with a line saying just "end".
 </pre>
 </section>
 
+<section class="slide">
+       <h2> Custom commands (2/2) </h2>
+        <p> You can create hooks which run just before or after any gdb command: </p>
+        <ul style="text-align:left;">
+            <li> <code>define hook-command</code> to run things <b>before</b> <code>command</code> </li>
+            <li> <code>define hookpost-command</code> to run things <b>after</b> <code>command</code> </li>
+
+</section>
+
+<section class="slide">
+    <h2>Did you know...?</h2>
+    <p> GDB has many other semi-unknown cool features (which I won't talk about today) </p>
+    <ul style="text-align:left;">
+        <li class="slide"> <h3>Reverse debugging</h3> records (some finite amount of) program history and allows backwards stepping/running.  </li>
+        <li class="slide"> <h3>JIT interface</h3>a JIT can generate debug symbols and pass them on-the-fly to gdb to ease debugging (supported by LLVM!). </li>
+    </ul>
+</section>
+
+
+
 <!-- End slides. -->
 
 
diff --git a/samples/explore.py b/samples/explore.py
new file mode 100644 (file)
index 0000000..f62be7d
--- /dev/null
@@ -0,0 +1,694 @@
+# 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_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'.\n" %
+               (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 ("\n'%s' is a pointer to a value of type '%s'" %
+               (expr, str(value.type.target())))
+        option  = raw_input("Do you want to explore it as an array or a "
+                            "single value pointer [a/s] : ")
+        if option == "s":
+            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)
+        if option == "a":
+            while True:
+                index = 0
+                try:
+                    index = int(raw_input("Enter the index you want to "
+                                          "explore in '%s': " % expr))
+                except ValueError:
+                    break
+                element_expr = "%s[%d]" % (Explorer.guard_expr(expr), index)
+                element = gdb.parse_and_eval(element_expr)
+                try:
+                    str(element)
+                except gdb.MemoryError:
+                    print "Cannot read value at index %d." % index
+                    continue
+                Explorer.explore_expr(element_expr, element, True)
+        if option != "s" and option != "a":    
+            if is_child:
+                Explorer.retur_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 of a pointer type pointing 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 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 elements of type '%s'." %
+               (expr, str(target_type)))
+        index = 0
+        try:
+            index = int(raw_input("Enter the index 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 type with elements of type '%s'." % 
+               (name, str(target_type)))
+
+        explore_type(target_type, "the array element of %s" % name, 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 explore_expr(expr, value, is_child):
+        """Function to explore structs/classes and union values.
+        See Explorer.explore_expr for more information.
+        """
+        type_code = value.type.code
+        type_desc = ""
+        if type_code == gdb.TYPE_CODE_STRUCT:
+            type_desc = "struct/class"
+        else:
+            type_desc = "union"
+        print("The value of '%s' is a %s of type '%s' with the following "
+              "fields:\n" % (expr, type_desc, str(value.type)))
+
+        fields = value.type.fields()
+        has_explorable_fields = False
+        choice_to_compound_field_map = { }
+        current_choice = 0
+        print_list = [ ]
+        for field in fields:
+            field_full_name = Explorer.guard_expr(expr) + "." + field.name
+            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"
+
+        if is_child:
+            print ("\n%s is a %s of type '%s' "
+                   "with the following fields:\n" %
+                   (name, type_desc, str(datatype)))
+        else:
+            print ("\n'%s' is a %s with the following "
+                   "fields:\n" %
+                   (name, type_desc))
+
+        fields = datatype.fields()
+        has_explorable_fields = False
+        current_choice = 0
+        choice_to_compound_field_map = { }
+        print_list = [ ]
+        for field in fields:
+            rhs = ("<Enter %d to explore this field of type %s>" %
+                   (current_choice, str(field.type)))
+            print_list.append((field.name, rhs))
+            choice_to_compound_field_map[str(current_choice)] = (
+                field.name, field.type)
+            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:
+                    Explorer.explore_type(
+                        ("field '%s' of %s" %
+                         (choice_to_compound_field_map[choice][0], name)),
+                        choice_to_compound_field_map[choice][1],
+                        True)
+                else:
+                    Explorer.explore_type(
+                        ("field '%s' of '%s'" %
+                         (choice_to_compound_field_map[choice][0], 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 ("\nThe 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("\nThe type of %s is a typedef of type '%s'." %
+                  (name, str(actual_type)))
+        else:
+            print("\nThe 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' command 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. Entering
+           an invalid input will also result in similar behaviour.
+    """
+
+    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. Entering
+           an invalid input will also result in similar behaviour.
+    """
+    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. Entering
+           an invalid input will also result in similar behaviour.
+    """
+
+    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()
diff --git a/samples/plist.gdb b/samples/plist.gdb
new file mode 100644 (file)
index 0000000..446c3a4
--- /dev/null
@@ -0,0 +1,9 @@
+define plist
+    set $ptr = $arg0
+    while $ptr != 0
+        print *$ptr
+        set $ptr = $ptr->next
+    end
+end
+
+
diff --git a/samples/script.py b/samples/script.py
new file mode 100644 (file)
index 0000000..d862955
--- /dev/null
@@ -0,0 +1,43 @@
+import gdb
+from PyQt4 import QtGui
+
+def print_node(node, recursion_level):
+    if len(node.type.fields()) == 0:
+        print "node = %s", str(node)
+        result = str(node)
+    else:
+        result = {}
+        for f in node.type.fields():
+            child = node[f.name]
+            if child.type.code == gdb.TYPE_CODE_PTR and recursion_level > 0:
+                if (child == 0):
+                    result_child = "NULL"
+                else:
+                    result_child = print_node(child.dereference(), recursion_level - 1)
+            else:
+                result_child = str(child)
+            result[f.name] = result_child
+    return result
+
+class ViewerCommand(gdb.Command):
+    """View data structures"""
+    def __init__(self):
+        super(ViewerCommand, self).__init__("view", gdb.COMMAND_DATA, gdb.COMPLETE_SYMBOL)
+
+
+    def invoke(self, arg, from_tty):
+        args = gdb.string_to_argv(arg)
+        value = gdb.parse_and_eval(args[0])
+        if len(args) > 1:
+            recursion_level = int(args[1])
+        else:
+            recursion_level = 3
+        print print_node(value.dereference(), recursion_level)
+
+        
+
+
+
+ViewerCommand()
+
+
index 06aff4c2481ead0b33fd6fedeed3ef7d13c6f1cf..351fbafd107fd717788e1aa2312f4fff1fcd8096 100644 (file)
@@ -3,12 +3,14 @@
 
 typedef struct snode {
        int value;
+        float blah;
        struct snode *next;
 } node;
 
 void add(node **head, int x) {
        node *n = malloc(sizeof(node));
        n->value = x;
+        n->blah = 1234.0f;
        n->next = *head;
        *head = n;
 }