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
19import gdb
20import sys
21
22if sys.version_info[0] > 2:
23    # Python 3 renamed raw_input to input
24    raw_input = input
25
26class 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
189class 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
234class 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
300class 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
322class 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
367class 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
550class 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
583class 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
649class 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
689class 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
720class 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
756Explorer.init_env()
757
758ExploreCommand()
759ExploreValueCommand()
760ExploreTypeCommand()
761