An interpreted, interactive, object-oriented programming language
CentOS Sources
2017-08-01 71084d584ff953f5463757ec6536406320560b4d
commit | author | age
6e8c2f 1 --- Tools/gdb/libpython.py.orig    2013-10-09 10:54:59.894701668 +0200
CB 2 +++ Tools/gdb/libpython.py    2013-10-09 11:09:30.278703290 +0200
3 @@ -1194,39 +1194,113 @@
4              iter_frame = iter_frame.newer()
5          return index
6  
7 +    # We divide frames into:
8 +    #   - "python frames":
9 +    #       - "bytecode frames" i.e. PyEval_EvalFrameEx
10 +    #       - "other python frames": things that are of interest from a python
11 +    #         POV, but aren't bytecode (e.g. GC, GIL)
12 +    #   - everything else
13 +
14 +    def is_python_frame(self):
15 +        '''Is this a PyEval_EvalFrameEx frame, or some other important
16 +        frame? (see is_other_python_frame for what "important" means in this
17 +        context)'''
18 +        if self.is_evalframeex():
19 +            return True
20 +        if self.is_other_python_frame():
21 +            return True
22 +        return False
23 +
24      def is_evalframeex(self):
25 -        '''Is this a PyEval_EvalFrameEx frame?'''
26 -        if self._gdbframe.name() == 'PyEval_EvalFrameEx':
27 -            '''
28 -            I believe we also need to filter on the inline
29 -            struct frame_id.inline_depth, only regarding frames with
30 -            an inline depth of 0 as actually being this function
31 -
32 -            So we reject those with type gdb.INLINE_FRAME
33 -            '''
34 -            if self._gdbframe.type() == gdb.NORMAL_FRAME:
35 -                # We have a PyEval_EvalFrameEx frame:
36 -                return True
37 +        if self._gdbframe.function():
38 +            if self._gdbframe.function().name == 'PyEval_EvalFrameEx':
39 +                '''
40 +                I believe we also need to filter on the inline
41 +                struct frame_id.inline_depth, only regarding frames with
42 +                an inline depth of 0 as actually being this function
43 +
44 +                So we reject those with type gdb.INLINE_FRAME
45 +                '''
46 +                if self._gdbframe.type() == gdb.NORMAL_FRAME:
47 +                    # We have a PyEval_EvalFrameEx frame:
48 +                    return True
49 +
50 +        return False
51 +
52 +    def is_other_python_frame(self):
53 +        '''Is this frame worth displaying in python backtraces?
54 +        Examples:
55 +          - waiting on the GIL
56 +          - garbage-collecting
57 +          - within a CFunction
58 +         If it is, return a descriptive string
59 +         For other frames, return False
60 +         '''
61 +        if self.is_waiting_for_gil():
62 +            return 'Waiting for a lock (e.g. GIL)'
63 +        elif self.is_gc_collect():
64 +            return 'Garbage-collecting'
65 +        else:
66 +            # Detect invocations of PyCFunction instances:
67 +            if self._gdbframe.name() == 'PyCFunction_Call':
68 +                try:
69 +                    func = self._gdbframe.read_var('func')
70 +                    # Use the prettyprinter for the func:
71 +                    return str(func)
72 +                except RuntimeError:
73 +                    return 'PyCFunction invocation (unable to read "func")'
74 +            older = self.older()
75 +            if older and older._gdbframe.name() == 'call_function':
76 +                # Within that frame:
77 +                # 'call_function' contains, amongst other things, a
78 +                # hand-inlined copy of PyCFunction_Call.
79 +                #   "func" is the local containing the PyObject* of the
80 +                # callable instance
81 +                # Report it, but only if it's a PyCFunction (since otherwise
82 +                # we'd be reporting an implementation detail of every other
83 +                # function invocation)
84 +                try:
85 +                    func = older._gdbframe.read_var('func')
86 +                    funcobj = PyObjectPtr.from_pyobject_ptr(func)
87 +                    if isinstance(funcobj, PyCFunctionObjectPtr):
88 +                        # Use the prettyprinter for the func:
89 +                        return str(func)
90 +                except RuntimeError:
91 +                    return False
92  
93 +        # This frame isn't worth reporting:
94          return False
95  
96 +    def is_waiting_for_gil(self):
97 +        '''Is this frame waiting for a lock?'''
98 +        framename = self._gdbframe.name()
99 +        if framename:
100 +            return 'pthread_cond_timedwait' in framename or \
101 +                   'PyThread_acquire_lock' in framename
102 +
103 +    def is_gc_collect(self):
104 +        '''Is this frame "collect" within the the garbage-collector?'''
105 +        return self._gdbframe.name() == 'collect'
106 +
107      def get_pyop(self):
108          try:
109              f = self._gdbframe.read_var('f')
110 -            frame = PyFrameObjectPtr.from_pyobject_ptr(f)
111 -            if not frame.is_optimized_out():
112 -                return frame
113 -            # gdb is unable to get the "f" argument of PyEval_EvalFrameEx()
114 -            # because it was "optimized out". Try to get "f" from the frame
115 -            # of the caller, PyEval_EvalCodeEx().
116 -            orig_frame = frame
117 -            caller = self._gdbframe.older()
118 -            if caller:
119 -                f = caller.read_var('f')
120 -                frame = PyFrameObjectPtr.from_pyobject_ptr(f)
121 -                if not frame.is_optimized_out():
122 -                    return frame
123 -            return orig_frame
124 +            obj = PyFrameObjectPtr.from_pyobject_ptr(f)
125 +            if isinstance(obj, PyFrameObjectPtr):
126 +                return obj
127 +            else:
128 +                return None
129 +        except ValueError:
130 +            return None
131 +
132 +    def get_py_co(self):
133 +        try:
134 +            co = self._gdbframe.read_var('co')
135 +            obj = PyCodeObjectPtr.from_pyobject_ptr(co)
136 +            if isinstance(obj, PyCodeObjectPtr):
137 +                return obj
138 +            else:
139 +                return None
140          except ValueError:
141              return None
142  
143 @@ -1239,8 +1313,22 @@
144  
145      @classmethod
146      def get_selected_python_frame(cls):
147 -        '''Try to obtain the Frame for the python code in the selected frame,
148 -        or None'''
149 +        '''Try to obtain the Frame for the python-related code in the selected
150 +        frame, or None'''
151 +        frame = cls.get_selected_frame()
152 +
153 +        while frame:
154 +            if frame.is_python_frame():
155 +                return frame
156 +            frame = frame.older()
157 +
158 +        # Not found:
159 +        return None
160 +
161 +    @classmethod
162 +    def get_selected_bytecode_frame(cls):
163 +        '''Try to obtain the Frame for the python bytecode interpreter in the
164 +        selected GDB frame, or None'''
165          frame = cls.get_selected_frame()
166  
167          while frame:
168 @@ -1265,7 +1353,11 @@
169              else:
170                  sys.stdout.write('#%i (unable to read python frame information)\n' % self.get_index())
171          else:
172 -            sys.stdout.write('#%i\n' % self.get_index())
173 +            info = self.is_other_python_frame()
174 +            if info:
175 +                sys.stdout.write('#%i %s\n' % (self.get_index(), info))
176 +            else:
177 +                sys.stdout.write('#%i\n' % self.get_index())
178  
179  class PyList(gdb.Command):
180      '''List the current Python source code, if any
181 @@ -1301,7 +1393,7 @@
182          if m:
183              start, end = map(int, m.groups())
184  
185 -        frame = Frame.get_selected_python_frame()
186 +        frame = Frame.get_selected_bytecode_frame()
187          if not frame:
188              print 'Unable to locate python frame'
189              return
190 @@ -1353,7 +1445,7 @@
191          if not iter_frame:
192              break
193  
194 -        if iter_frame.is_evalframeex():
195 +        if iter_frame.is_python_frame():
196              # Result:
197              if iter_frame.select():
198                  iter_frame.print_summary()
199 @@ -1407,7 +1499,7 @@
200      def invoke(self, args, from_tty):
201          frame = Frame.get_selected_python_frame()
202          while frame:
203 -            if frame.is_evalframeex():
204 +            if frame.is_python_frame():
205                  frame.print_summary()
206              frame = frame.older()
207