1import linecache
2import os.path
3import re
4
5from _pydev_bundle import pydev_log
6from _pydevd_bundle import pydevd_dont_trace
7from _pydevd_bundle.pydevd_constants import (dict_iter_values, IS_PY3K, RETURN_VALUES_DICT, NO_FTRACE,
8    EXCEPTION_TYPE_HANDLED, EXCEPTION_TYPE_USER_UNHANDLED)
9from _pydevd_bundle.pydevd_frame_utils import add_exception_to_frame, just_raised, remove_exception_from_frame, ignore_exception_trace
10from _pydevd_bundle.pydevd_utils import get_clsname_for_code
11from pydevd_file_utils import get_abs_path_real_path_and_base_from_frame
12from _pydevd_bundle.pydevd_comm_constants import constant_to_str, CMD_SET_FUNCTION_BREAK
13try:
14    from _pydevd_bundle.pydevd_bytecode_utils import get_smart_step_into_variant_from_frame_offset
15except ImportError:
16
17    def get_smart_step_into_variant_from_frame_offset(*args, **kwargs):
18        return None
19
20# IFDEF CYTHON
21# cython_inline_constant: CMD_STEP_INTO = 107
22# cython_inline_constant: CMD_STEP_INTO_MY_CODE = 144
23# cython_inline_constant: CMD_STEP_RETURN = 109
24# cython_inline_constant: CMD_STEP_RETURN_MY_CODE = 160
25# cython_inline_constant: CMD_STEP_OVER = 108
26# cython_inline_constant: CMD_STEP_OVER_MY_CODE = 159
27# cython_inline_constant: CMD_STEP_CAUGHT_EXCEPTION = 137
28# cython_inline_constant: CMD_SET_BREAK = 111
29# cython_inline_constant: CMD_SMART_STEP_INTO = 128
30# cython_inline_constant: CMD_STEP_INTO_COROUTINE = 206
31# cython_inline_constant: STATE_RUN = 1
32# cython_inline_constant: STATE_SUSPEND = 2
33# ELSE
34# Note: those are now inlined on cython.
35CMD_STEP_INTO = 107
36CMD_STEP_INTO_MY_CODE = 144
37CMD_STEP_RETURN = 109
38CMD_STEP_RETURN_MY_CODE = 160
39CMD_STEP_OVER = 108
40CMD_STEP_OVER_MY_CODE = 159
41CMD_STEP_CAUGHT_EXCEPTION = 137
42CMD_SET_BREAK = 111
43CMD_SMART_STEP_INTO = 128
44CMD_STEP_INTO_COROUTINE = 206
45STATE_RUN = 1
46STATE_SUSPEND = 2
47# ENDIF
48
49basename = os.path.basename
50
51IGNORE_EXCEPTION_TAG = re.compile('[^#]*#.*@IgnoreException')
52DEBUG_START = ('pydevd.py', 'run')
53DEBUG_START_PY3K = ('_pydev_execfile.py', 'execfile')
54TRACE_PROPERTY = 'pydevd_traceproperty.py'
55
56import dis
57
58try:
59    StopAsyncIteration
60except NameError:
61    StopAsyncIteration = StopIteration
62
63
64# IFDEF CYTHON
65# cdef is_unhandled_exception(container_obj, py_db, frame, int last_raise_line, set raise_lines):
66# ELSE
67def is_unhandled_exception(container_obj, py_db, frame, last_raise_line, raise_lines):
68# ENDIF
69    if frame.f_lineno in raise_lines:
70        return True
71
72    else:
73        try_except_infos = container_obj.try_except_infos
74        if try_except_infos is None:
75            container_obj.try_except_infos = try_except_infos = py_db.collect_try_except_info(frame.f_code)
76
77        if not try_except_infos:
78            # Consider the last exception as unhandled because there's no try..except in it.
79            return True
80        else:
81            # Now, consider only the try..except for the raise
82            valid_try_except_infos = []
83            for try_except_info in try_except_infos:
84                if try_except_info.is_line_in_try_block(last_raise_line):
85                    valid_try_except_infos.append(try_except_info)
86
87            if not valid_try_except_infos:
88                return True
89
90            else:
91                # Note: check all, not only the "valid" ones to cover the case
92                # in "tests_python.test_tracing_on_top_level.raise_unhandled10"
93                # where one try..except is inside the other with only a raise
94                # and it's gotten in the except line.
95                for try_except_info in try_except_infos:
96                    if try_except_info.is_line_in_except_block(frame.f_lineno):
97                        if (
98                                frame.f_lineno == try_except_info.except_line or
99                                frame.f_lineno in try_except_info.raise_lines_in_except
100                            ):
101                            # In a raise inside a try..except block or some except which doesn't
102                            # match the raised exception.
103                            return True
104    return False
105
106
107# IFDEF CYTHON
108# cdef class _TryExceptContainerObj:
109#     cdef public list try_except_infos;
110#     def __init__(self):
111#         self.try_except_infos = None
112# ELSE
113class _TryExceptContainerObj(object):
114    '''
115    A dumb container object just to containe the try..except info when needed. Meant to be
116    persisent among multiple PyDBFrames to the same code object.
117    '''
118    try_except_infos = None
119# ENDIF
120
121
122#=======================================================================================================================
123# PyDBFrame
124#=======================================================================================================================
125# IFDEF CYTHON
126# cdef class PyDBFrame:
127# ELSE
128class PyDBFrame:
129    '''This makes the tracing for a given frame, so, the trace_dispatch
130    is used initially when we enter into a new context ('call') and then
131    is reused for the entire context.
132    '''
133# ENDIF
134
135    # Note: class (and not instance) attributes.
136
137    # Same thing in the main debugger but only considering the file contents, while the one in the main debugger
138    # considers the user input (so, the actual result must be a join of both).
139    filename_to_lines_where_exceptions_are_ignored = {}
140    filename_to_stat_info = {}
141
142    # IFDEF CYTHON
143    # cdef tuple _args
144    # cdef int should_skip
145    # cdef object exc_info
146    # def __init__(self, tuple args):
147        # self._args = args # In the cython version we don't need to pass the frame
148        # self.should_skip = -1  # On cythonized version, put in instance.
149        # self.exc_info = ()
150    # ELSE
151    should_skip = -1  # Default value in class (put in instance on set).
152    exc_info = ()  # Default value in class (put in instance on set).
153
154    def __init__(self, args):
155        # args = main_debugger, abs_path_canonical_path_and_base, base, info, t, frame
156        # yeap, much faster than putting in self and then getting it from self later on
157        self._args = args
158    # ENDIF
159
160    def set_suspend(self, *args, **kwargs):
161        self._args[0].set_suspend(*args, **kwargs)
162
163    def do_wait_suspend(self, *args, **kwargs):
164        self._args[0].do_wait_suspend(*args, **kwargs)
165
166    # IFDEF CYTHON
167    # def trace_exception(self, frame, str event, arg):
168    #     cdef bint should_stop;
169    #     cdef tuple exc_info;
170    # ELSE
171    def trace_exception(self, frame, event, arg):
172    # ENDIF
173        if event == 'exception':
174            should_stop, frame = self._should_stop_on_exception(frame, event, arg)
175
176            if should_stop:
177                if self._handle_exception(frame, event, arg, EXCEPTION_TYPE_HANDLED):
178                    return self.trace_dispatch
179
180        elif event == 'return':
181            exc_info = self.exc_info
182            if exc_info and arg is None:
183                frame_skips_cache, frame_cache_key = self._args[4], self._args[5]
184                custom_key = (frame_cache_key, 'try_exc_info')
185                container_obj = frame_skips_cache.get(custom_key)
186                if container_obj is None:
187                    container_obj = frame_skips_cache[custom_key] = _TryExceptContainerObj()
188                if is_unhandled_exception(container_obj, self._args[0], frame, exc_info[1], exc_info[2]) and \
189                        self.handle_user_exception(frame):
190                    return self.trace_dispatch
191
192        return self.trace_exception
193
194    # IFDEF CYTHON
195    # cdef _should_stop_on_exception(self, frame, str event, arg):
196    #     cdef PyDBAdditionalThreadInfo info;
197    #     cdef bint should_stop;
198    #     cdef bint was_just_raised;
199    #     cdef list check_excs;
200    # ELSE
201    def _should_stop_on_exception(self, frame, event, arg):
202    # ENDIF
203
204        # main_debugger, _filename, info, _thread = self._args
205        main_debugger = self._args[0]
206        info = self._args[2]
207        should_stop = False
208
209        # STATE_SUSPEND = 2
210        if info.pydev_state != 2:  # and breakpoint is not None:
211            exception, value, trace = arg
212
213            if trace is not None and hasattr(trace, 'tb_next'):
214                # on jython trace is None on the first event and it may not have a tb_next.
215
216                should_stop = False
217                exception_breakpoint = None
218                try:
219                    if main_debugger.plugin is not None:
220                        result = main_debugger.plugin.exception_break(main_debugger, self, frame, self._args, arg)
221                        if result:
222                            should_stop, frame = result
223                except:
224                    pydev_log.exception()
225
226                if not should_stop:
227                    # Apply checks that don't need the exception breakpoint (where we shouldn't ever stop).
228                    if exception == SystemExit and main_debugger.ignore_system_exit_code(value):
229                        pass
230
231                    elif exception in (GeneratorExit, StopIteration, StopAsyncIteration):
232                        # These exceptions are control-flow related (they work as a generator
233                        # pause), so, we shouldn't stop on them.
234                        pass
235
236                    elif ignore_exception_trace(trace):
237                        pass
238
239                    else:
240                        was_just_raised = trace.tb_next is None
241
242                        # It was not handled by any plugin, lets check exception breakpoints.
243                        check_excs = []
244
245                        # Note: check user unhandled before regular exceptions.
246                        exc_break_user = main_debugger.get_exception_breakpoint(
247                            exception, main_debugger.break_on_user_uncaught_exceptions)
248                        if exc_break_user is not None:
249                            check_excs.append((exc_break_user, True))
250
251                        exc_break_caught = main_debugger.get_exception_breakpoint(
252                            exception, main_debugger.break_on_caught_exceptions)
253                        if exc_break_caught is not None:
254                            check_excs.append((exc_break_caught, False))
255
256                        for exc_break, is_user_uncaught in check_excs:
257                            # Initially mark that it should stop and then go into exclusions.
258                            should_stop = True
259
260                            if main_debugger.exclude_exception_by_filter(exc_break, trace):
261                                pydev_log.debug("Ignore exception %s in library %s -- (%s)" % (exception, frame.f_code.co_filename, frame.f_code.co_name))
262                                should_stop = False
263
264                            elif exc_break.condition is not None and \
265                                    not main_debugger.handle_breakpoint_condition(info, exc_break, frame):
266                                should_stop = False
267
268                            elif is_user_uncaught:
269                                # Note: we don't stop here, we just collect the exc_info to use later on...
270                                should_stop = False
271                                if not main_debugger.apply_files_filter(frame, frame.f_code.co_filename, True) \
272                                        and (frame.f_back is None or main_debugger.apply_files_filter(frame.f_back, frame.f_back.f_code.co_filename, True)):
273                                    # User uncaught means that we're currently in user code but the code
274                                    # up the stack is library code.
275                                    exc_info = self.exc_info
276                                    if not exc_info:
277                                        exc_info = (arg, frame.f_lineno, set([frame.f_lineno]))
278                                    else:
279                                        lines = exc_info[2]
280                                        lines.add(frame.f_lineno)
281                                        exc_info = (arg, frame.f_lineno, lines)
282                                    self.exc_info = exc_info
283                            else:
284                                # I.e.: these are only checked if we're not dealing with user uncaught exceptions.
285                                if exc_break.notify_on_first_raise_only and main_debugger.skip_on_exceptions_thrown_in_same_context \
286                                        and not was_just_raised and not just_raised(trace.tb_next):
287                                    # In this case we never stop if it was just raised, so, to know if it was the first we
288                                    # need to check if we're in the 2nd method.
289                                    should_stop = False  # I.e.: we stop only when we're at the caller of a method that throws an exception
290
291                                elif exc_break.notify_on_first_raise_only and not main_debugger.skip_on_exceptions_thrown_in_same_context \
292                                        and not was_just_raised:
293                                    should_stop = False  # I.e.: we stop only when it was just raised
294
295                                elif was_just_raised and main_debugger.skip_on_exceptions_thrown_in_same_context:
296                                    # Option: Don't break if an exception is caught in the same function from which it is thrown
297                                    should_stop = False
298
299                            if should_stop:
300                                exception_breakpoint = exc_break
301                                try:
302                                    info.pydev_message = exc_break.qname
303                                except:
304                                    info.pydev_message = exc_break.qname.encode('utf-8')
305                                break
306
307                if should_stop:
308                    # Always add exception to frame (must remove later after we proceed).
309                    add_exception_to_frame(frame, (exception, value, trace))
310
311                    if exception_breakpoint is not None and exception_breakpoint.expression is not None:
312                        main_debugger.handle_breakpoint_expression(exception_breakpoint, info, frame)
313
314        return should_stop, frame
315
316    def handle_user_exception(self, frame):
317        exc_info = self.exc_info
318        if exc_info:
319            return self._handle_exception(frame, 'exception', exc_info[0], EXCEPTION_TYPE_USER_UNHANDLED)
320        return False
321
322    # IFDEF CYTHON
323    # cdef _handle_exception(self, frame, str event, arg, str exception_type):
324    #     cdef bint stopped;
325    #     cdef tuple abs_real_path_and_base;
326    #     cdef str absolute_filename;
327    #     cdef str canonical_normalized_filename;
328    #     cdef dict filename_to_lines_where_exceptions_are_ignored;
329    #     cdef dict lines_ignored;
330    #     cdef dict frame_id_to_frame;
331    #     cdef dict merged;
332    #     cdef object trace_obj;
333    #     cdef object main_debugger;
334    # ELSE
335    def _handle_exception(self, frame, event, arg, exception_type):
336    # ENDIF
337        stopped = False
338        try:
339            # print('_handle_exception', frame.f_lineno, frame.f_code.co_name)
340
341            # We have 3 things in arg: exception type, description, traceback object
342            trace_obj = arg[2]
343            main_debugger = self._args[0]
344
345            initial_trace_obj = trace_obj
346            if trace_obj.tb_next is None and trace_obj.tb_frame is frame:
347                # I.e.: tb_next should be only None in the context it was thrown (trace_obj.tb_frame is frame is just a double check).
348                pass
349            else:
350                # Get the trace_obj from where the exception was raised...
351                while trace_obj.tb_next is not None:
352                    trace_obj = trace_obj.tb_next
353
354            if main_debugger.ignore_exceptions_thrown_in_lines_with_ignore_exception:
355                for check_trace_obj in (initial_trace_obj, trace_obj):
356                    abs_real_path_and_base = get_abs_path_real_path_and_base_from_frame(check_trace_obj.tb_frame)
357                    absolute_filename = abs_real_path_and_base[0]
358                    canonical_normalized_filename = abs_real_path_and_base[1]
359
360                    filename_to_lines_where_exceptions_are_ignored = self.filename_to_lines_where_exceptions_are_ignored
361
362                    lines_ignored = filename_to_lines_where_exceptions_are_ignored.get(canonical_normalized_filename)
363                    if lines_ignored is None:
364                        lines_ignored = filename_to_lines_where_exceptions_are_ignored[canonical_normalized_filename] = {}
365
366                    try:
367                        curr_stat = os.stat(absolute_filename)
368                        curr_stat = (curr_stat.st_size, curr_stat.st_mtime)
369                    except:
370                        curr_stat = None
371
372                    last_stat = self.filename_to_stat_info.get(absolute_filename)
373                    if last_stat != curr_stat:
374                        self.filename_to_stat_info[absolute_filename] = curr_stat
375                        lines_ignored.clear()
376                        try:
377                            linecache.checkcache(absolute_filename)
378                        except:
379                            # Jython 2.1
380                            linecache.checkcache()
381
382                    from_user_input = main_debugger.filename_to_lines_where_exceptions_are_ignored.get(canonical_normalized_filename)
383                    if from_user_input:
384                        merged = {}
385                        merged.update(lines_ignored)
386                        # Override what we have with the related entries that the user entered
387                        merged.update(from_user_input)
388                    else:
389                        merged = lines_ignored
390
391                    exc_lineno = check_trace_obj.tb_lineno
392
393                    # print ('lines ignored', lines_ignored)
394                    # print ('user input', from_user_input)
395                    # print ('merged', merged, 'curr', exc_lineno)
396
397                    if exc_lineno not in merged:  # Note: check on merged but update lines_ignored.
398                        try:
399                            line = linecache.getline(absolute_filename, exc_lineno, check_trace_obj.tb_frame.f_globals)
400                        except:
401                            # Jython 2.1
402                            line = linecache.getline(absolute_filename, exc_lineno)
403
404                        if IGNORE_EXCEPTION_TAG.match(line) is not None:
405                            lines_ignored[exc_lineno] = 1
406                            return False
407                        else:
408                            # Put in the cache saying not to ignore
409                            lines_ignored[exc_lineno] = 0
410                    else:
411                        # Ok, dict has it already cached, so, let's check it...
412                        if merged.get(exc_lineno, 0):
413                            return False
414
415            thread = self._args[3]
416
417            try:
418                frame_id_to_frame = {}
419                frame_id_to_frame[id(frame)] = frame
420                f = trace_obj.tb_frame
421                while f is not None:
422                    frame_id_to_frame[id(f)] = f
423                    f = f.f_back
424                f = None
425
426                stopped = True
427                main_debugger.send_caught_exception_stack(thread, arg, id(frame))
428                try:
429                    self.set_suspend(thread, CMD_STEP_CAUGHT_EXCEPTION)
430                    self.do_wait_suspend(thread, frame, event, arg, exception_type=exception_type)
431                finally:
432                    main_debugger.send_caught_exception_stack_proceeded(thread)
433            except:
434                pydev_log.exception()
435
436            main_debugger.set_trace_for_frame_and_parents(frame)
437        finally:
438            # Make sure the user cannot see the '__exception__' we added after we leave the suspend state.
439            remove_exception_from_frame(frame)
440            # Clear some local variables...
441            frame = None
442            trace_obj = None
443            initial_trace_obj = None
444            check_trace_obj = None
445            f = None
446            frame_id_to_frame = None
447            main_debugger = None
448            thread = None
449
450        return stopped
451
452    # IFDEF CYTHON
453    # cdef get_func_name(self, frame):
454    #     cdef str func_name
455    # ELSE
456    def get_func_name(self, frame):
457    # ENDIF
458        code_obj = frame.f_code
459        func_name = code_obj.co_name
460        try:
461            cls_name = get_clsname_for_code(code_obj, frame)
462            if cls_name is not None:
463                return "%s.%s" % (cls_name, func_name)
464            else:
465                return func_name
466        except:
467            pydev_log.exception()
468            return func_name
469
470    # IFDEF CYTHON
471    # cdef _show_return_values(self, frame, arg):
472    # ELSE
473    def _show_return_values(self, frame, arg):
474    # ENDIF
475        try:
476            try:
477                f_locals_back = getattr(frame.f_back, "f_locals", None)
478                if f_locals_back is not None:
479                    return_values_dict = f_locals_back.get(RETURN_VALUES_DICT, None)
480                    if return_values_dict is None:
481                        return_values_dict = {}
482                        f_locals_back[RETURN_VALUES_DICT] = return_values_dict
483                    name = self.get_func_name(frame)
484                    return_values_dict[name] = arg
485            except:
486                pydev_log.exception()
487        finally:
488            f_locals_back = None
489
490    # IFDEF CYTHON
491    # cdef _remove_return_values(self, main_debugger, frame):
492    # ELSE
493    def _remove_return_values(self, main_debugger, frame):
494    # ENDIF
495        try:
496            try:
497                # Showing return values was turned off, we should remove them from locals dict.
498                # The values can be in the current frame or in the back one
499                frame.f_locals.pop(RETURN_VALUES_DICT, None)
500
501                f_locals_back = getattr(frame.f_back, "f_locals", None)
502                if f_locals_back is not None:
503                    f_locals_back.pop(RETURN_VALUES_DICT, None)
504            except:
505                pydev_log.exception()
506        finally:
507            f_locals_back = None
508
509    # IFDEF CYTHON
510    # cdef _get_unfiltered_back_frame(self, main_debugger, frame):
511    # ELSE
512    def _get_unfiltered_back_frame(self, main_debugger, frame):
513    # ENDIF
514        f = frame.f_back
515        while f is not None:
516            if not main_debugger.is_files_filter_enabled:
517                return f
518
519            else:
520                if main_debugger.apply_files_filter(f, f.f_code.co_filename, False):
521                    f = f.f_back
522
523                else:
524                    return f
525
526        return f
527
528    # IFDEF CYTHON
529    # cpdef trace_dispatch(self, frame, str event, arg):
530    #     cdef tuple abs_path_canonical_path_and_base;
531    #     cdef bint is_exception_event;
532    #     cdef bint has_exception_breakpoints;
533    #     cdef bint can_skip;
534    #     cdef bint stop;
535    #     cdef PyDBAdditionalThreadInfo info;
536    #     cdef int step_cmd;
537    #     cdef int line;
538    #     cdef bint is_line;
539    #     cdef bint is_call;
540    #     cdef bint is_return;
541    #     cdef bint should_stop;
542    #     cdef dict breakpoints_for_file;
543    #     cdef dict stop_info;
544    #     cdef str curr_func_name;
545    #     cdef bint exist_result;
546    #     cdef dict frame_skips_cache;
547    #     cdef tuple frame_cache_key;
548    #     cdef tuple line_cache_key;
549    #     cdef int breakpoints_in_line_cache;
550    #     cdef int breakpoints_in_frame_cache;
551    #     cdef bint has_breakpoint_in_frame;
552    #     cdef bint is_coroutine_or_generator;
553    #     cdef int bp_line;
554    #     cdef object bp;
555    #     cdef int pydev_smart_parent_offset
556    #     cdef int pydev_smart_child_offset
557    #     cdef tuple pydev_smart_step_into_variants
558    # ELSE
559    def trace_dispatch(self, frame, event, arg):
560    # ENDIF
561        # Note: this is a big function because most of the logic related to hitting a breakpoint and
562        # stepping is contained in it. Ideally this could be split among multiple functions, but the
563        # problem in this case is that in pure-python function calls are expensive and even more so
564        # when tracing is on (because each function call will get an additional tracing call). We
565        # try to address this by using the info.is_tracing for the fastest possible return, but the
566        # cost is still high (maybe we could use code-generation in the future and make the code
567        # generation be better split among what each part does).
568
569        # DEBUG = '_debugger_case_generator.py' in frame.f_code.co_filename
570        main_debugger, abs_path_canonical_path_and_base, info, thread, frame_skips_cache, frame_cache_key = self._args
571        # if DEBUG: print('frame trace_dispatch %s %s %s %s %s %s, stop: %s' % (frame.f_lineno, frame.f_code.co_name, frame.f_code.co_filename, event, constant_to_str(info.pydev_step_cmd), arg, info.pydev_step_stop))
572        try:
573            info.is_tracing += 1
574            line = frame.f_lineno
575            line_cache_key = (frame_cache_key, line)
576
577            if main_debugger.pydb_disposed:
578                return None if event == 'call' else NO_FTRACE
579
580            plugin_manager = main_debugger.plugin
581            has_exception_breakpoints = (
582                main_debugger.break_on_caught_exceptions
583                or main_debugger.break_on_user_uncaught_exceptions
584                or main_debugger.has_plugin_exception_breaks)
585
586            stop_frame = info.pydev_step_stop
587            step_cmd = info.pydev_step_cmd
588            function_breakpoint_on_call_event = None
589
590            if frame.f_code.co_flags & 0xa0:  # 0xa0 ==  CO_GENERATOR = 0x20 | CO_COROUTINE = 0x80
591                # Dealing with coroutines and generators:
592                # When in a coroutine we change the perceived event to the debugger because
593                # a call, StopIteration exception and return are usually just pausing/unpausing it.
594                if event == 'line':
595                    is_line = True
596                    is_call = False
597                    is_return = False
598                    is_exception_event = False
599
600                elif event == 'return':
601                    is_line = False
602                    is_call = False
603                    is_return = True
604                    is_exception_event = False
605
606                    returns_cache_key = (frame_cache_key, 'returns')
607                    return_lines = frame_skips_cache.get(returns_cache_key)
608                    if return_lines is None:
609                        # Note: we're collecting the return lines by inspecting the bytecode as
610                        # there are multiple returns and multiple stop iterations when awaiting and
611                        # it doesn't give any clear indication when a coroutine or generator is
612                        # finishing or just pausing.
613                        return_lines = set()
614                        for x in main_debugger.collect_return_info(frame.f_code):
615                            # Note: cython does not support closures in cpdefs (so we can't use
616                            # a list comprehension).
617                            return_lines.add(x.return_line)
618
619                        frame_skips_cache[returns_cache_key] = return_lines
620
621                    if line not in return_lines:
622                        # Not really a return (coroutine/generator paused).
623                        return self.trace_dispatch
624                    else:
625                        if self.exc_info:
626                            self.handle_user_exception(frame)
627                            return self.trace_dispatch
628
629                        # Tricky handling: usually when we're on a frame which is about to exit
630                        # we set the step mode to step into, but in this case we'd end up in the
631                        # asyncio internal machinery, which is not what we want, so, we just
632                        # ask the stop frame to be a level up.
633                        #
634                        # Note that there's an issue here which we may want to fix in the future: if
635                        # the back frame is a frame which is filtered, we won't stop properly.
636                        # Solving this may not be trivial as we'd need to put a scope in the step
637                        # in, but we may have to do it anyways to have a step in which doesn't end
638                        # up in asyncio).
639                        if stop_frame is frame:
640                            if step_cmd in (CMD_STEP_OVER, CMD_STEP_OVER_MY_CODE, CMD_STEP_INTO, CMD_STEP_INTO_MY_CODE):
641                                f = self._get_unfiltered_back_frame(main_debugger, frame)
642                                if f is not None:
643                                    info.pydev_step_cmd = CMD_STEP_INTO_COROUTINE
644                                    info.pydev_step_stop = f
645                                else:
646                                    if step_cmd == CMD_STEP_OVER:
647                                        info.pydev_step_cmd = CMD_STEP_INTO
648                                        info.pydev_step_stop = None
649
650                                    elif step_cmd == CMD_STEP_OVER_MY_CODE:
651                                        info.pydev_step_cmd = CMD_STEP_INTO_MY_CODE
652                                        info.pydev_step_stop = None
653
654                            elif step_cmd == CMD_STEP_INTO_COROUTINE:
655                                # We're exiting this one, so, mark the new coroutine context.
656                                f = self._get_unfiltered_back_frame(main_debugger, frame)
657                                if f is not None:
658                                    info.pydev_step_stop = f
659                                else:
660                                    info.pydev_step_cmd = CMD_STEP_INTO
661                                    info.pydev_step_stop = None
662
663                elif event == 'exception':
664                    breakpoints_for_file = None
665                    if has_exception_breakpoints:
666                        should_stop, frame = self._should_stop_on_exception(frame, event, arg)
667                        if should_stop:
668                            if self._handle_exception(frame, event, arg, EXCEPTION_TYPE_HANDLED):
669                                return self.trace_dispatch
670
671                    return self.trace_dispatch
672                else:
673                    # event == 'call' or event == 'c_XXX'
674                    return self.trace_dispatch
675
676            else:
677                if event == 'line':
678                    is_line = True
679                    is_call = False
680                    is_return = False
681                    is_exception_event = False
682
683                elif event == 'return':
684                    is_line = False
685                    is_return = True
686                    is_call = False
687                    is_exception_event = False
688
689                    # If we are in single step mode and something causes us to exit the current frame, we need to make sure we break
690                    # eventually.  Force the step mode to step into and the step stop frame to None.
691                    # I.e.: F6 in the end of a function should stop in the next possible position (instead of forcing the user
692                    # to make a step in or step over at that location).
693                    # Note: this is especially troublesome when we're skipping code with the
694                    # @DontTrace comment.
695                    if stop_frame is frame and is_return and step_cmd in (CMD_STEP_OVER, CMD_STEP_RETURN, CMD_STEP_OVER_MY_CODE, CMD_STEP_RETURN_MY_CODE, CMD_SMART_STEP_INTO):
696                        if step_cmd in (CMD_STEP_OVER, CMD_STEP_RETURN, CMD_SMART_STEP_INTO):
697                            info.pydev_step_cmd = CMD_STEP_INTO
698                        else:
699                            info.pydev_step_cmd = CMD_STEP_INTO_MY_CODE
700                        info.pydev_step_stop = None
701
702                    if self.exc_info:
703                        if self.handle_user_exception(frame):
704                            return self.trace_dispatch
705
706                elif event == 'call':
707                    is_line = False
708                    is_call = True
709                    is_return = False
710                    is_exception_event = False
711                    if frame.f_code.co_firstlineno == frame.f_lineno:  # Check line to deal with async/await.
712                        function_breakpoint_on_call_event = main_debugger.function_breakpoint_name_to_breakpoint.get(frame.f_code.co_name)
713
714                elif event == 'exception':
715                    is_exception_event = True
716                    breakpoints_for_file = None
717                    if has_exception_breakpoints:
718                        should_stop, frame = self._should_stop_on_exception(frame, event, arg)
719                        if should_stop:
720                            if self._handle_exception(frame, event, arg, EXCEPTION_TYPE_HANDLED):
721                                return self.trace_dispatch
722                    is_line = False
723                    is_return = False
724                    is_call = False
725
726                else:
727                    # Unexpected: just keep the same trace func (i.e.: event == 'c_XXX').
728                    return self.trace_dispatch
729
730            if not is_exception_event:
731                breakpoints_for_file = main_debugger.breakpoints.get(abs_path_canonical_path_and_base[1])
732
733                can_skip = False
734
735                if info.pydev_state == 1:  # STATE_RUN = 1
736                    # we can skip if:
737                    # - we have no stop marked
738                    # - we should make a step return/step over and we're not in the current frame
739                    # - we're stepping into a coroutine context and we're not in that context
740                    if step_cmd == -1:
741                        can_skip = True
742
743                    elif step_cmd in (CMD_STEP_OVER, CMD_STEP_RETURN, CMD_STEP_OVER_MY_CODE, CMD_STEP_RETURN_MY_CODE) and stop_frame is not frame:
744                        can_skip = True
745
746                    elif step_cmd == CMD_SMART_STEP_INTO and (
747                            stop_frame is not None and
748                            stop_frame is not frame and
749                            stop_frame is not frame.f_back and
750                            (frame.f_back is None or stop_frame is not frame.f_back.f_back)):
751                        can_skip = True
752
753                    elif step_cmd == CMD_STEP_INTO_MY_CODE:
754                        if (
755                            main_debugger.apply_files_filter(frame, frame.f_code.co_filename, True)
756                            and (frame.f_back is None or main_debugger.apply_files_filter(frame.f_back, frame.f_back.f_code.co_filename, True))
757                            ):
758                                can_skip = True
759
760                    elif step_cmd == CMD_STEP_INTO_COROUTINE:
761                        f = frame
762                        while f is not None:
763                            if f is stop_frame:
764                                break
765                            f = f.f_back
766                        else:
767                            can_skip = True
768
769                    if can_skip:
770                        if plugin_manager is not None and (
771                                main_debugger.has_plugin_line_breaks or main_debugger.has_plugin_exception_breaks):
772                            can_skip = plugin_manager.can_skip(main_debugger, frame)
773
774                        if can_skip and main_debugger.show_return_values and info.pydev_step_cmd in (CMD_STEP_OVER, CMD_STEP_OVER_MY_CODE) and frame.f_back is stop_frame:
775                            # trace function for showing return values after step over
776                            can_skip = False
777
778                # Let's check to see if we are in a function that has a breakpoint. If we don't have a breakpoint,
779                # we will return nothing for the next trace
780                # also, after we hit a breakpoint and go to some other debugging state, we have to force the set trace anyway,
781                # so, that's why the additional checks are there.
782
783                if function_breakpoint_on_call_event:
784                    pass  # Do nothing here (just keep on going as we can't skip it).
785
786                elif not breakpoints_for_file:
787                    if can_skip:
788                        if has_exception_breakpoints:
789                            return self.trace_exception
790                        else:
791                            return None if is_call else NO_FTRACE
792
793                else:
794                    # When cached, 0 means we don't have a breakpoint and 1 means we have.
795                    if can_skip:
796                        breakpoints_in_line_cache = frame_skips_cache.get(line_cache_key, -1)
797                        if breakpoints_in_line_cache == 0:
798                            return self.trace_dispatch
799
800                    breakpoints_in_frame_cache = frame_skips_cache.get(frame_cache_key, -1)
801                    if breakpoints_in_frame_cache != -1:
802                        # Gotten from cache.
803                        has_breakpoint_in_frame = breakpoints_in_frame_cache == 1
804
805                    else:
806                        has_breakpoint_in_frame = False
807
808                        try:
809                            func_lines = set()
810                            for offset_and_lineno in dis.findlinestarts(frame.f_code):
811                                func_lines.add(offset_and_lineno[1])
812                        except:
813                            # This is a fallback for implementations where we can't get the function
814                            # lines -- i.e.: jython (in this case clients need to provide the function
815                            # name to decide on the skip or we won't be able to skip the function
816                            # completely).
817
818                            # Checks the breakpoint to see if there is a context match in some function.
819                            curr_func_name = frame.f_code.co_name
820
821                            # global context is set with an empty name
822                            if curr_func_name in ('?', '<module>', '<lambda>'):
823                                curr_func_name = ''
824
825                            for bp in dict_iter_values(breakpoints_for_file):  # jython does not support itervalues()
826                                # will match either global or some function
827                                if bp.func_name in ('None', curr_func_name):
828                                    has_breakpoint_in_frame = True
829                                    break
830                        else:
831                            for bp_line in breakpoints_for_file:  # iterate on keys
832                                if bp_line in func_lines:
833                                    has_breakpoint_in_frame = True
834                                    break
835
836                        # Cache the value (1 or 0 or -1 for default because of cython).
837                        if has_breakpoint_in_frame:
838                            frame_skips_cache[frame_cache_key] = 1
839                        else:
840                            frame_skips_cache[frame_cache_key] = 0
841
842                    if can_skip and not has_breakpoint_in_frame:
843                        if has_exception_breakpoints:
844                            return self.trace_exception
845                        else:
846                            return None if is_call else NO_FTRACE
847
848            # We may have hit a breakpoint or we are already in step mode. Either way, let's check what we should do in this frame
849            # if DEBUG: print('NOT skipped: %s %s %s %s' % (frame.f_lineno, frame.f_code.co_name, event, frame.__class__.__name__))
850
851            try:
852                flag = False
853                # return is not taken into account for breakpoint hit because we'd have a double-hit in this case
854                # (one for the line and the other for the return).
855
856                stop_info = {}
857                breakpoint = None
858                exist_result = False
859                stop = False
860                stop_reason = CMD_SET_BREAK
861                bp_type = None
862
863                if function_breakpoint_on_call_event:
864                    breakpoint = function_breakpoint_on_call_event
865                    stop = True
866                    new_frame = frame
867                    stop_reason = CMD_SET_FUNCTION_BREAK
868
869                elif not is_return and info.pydev_state != STATE_SUSPEND and breakpoints_for_file is not None and line in breakpoints_for_file:
870                    breakpoint = breakpoints_for_file[line]
871                    new_frame = frame
872                    stop = True
873                    if step_cmd in (CMD_STEP_OVER, CMD_STEP_OVER_MY_CODE) and (stop_frame is frame and is_line):
874                        stop = False  # we don't stop on breakpoint if we have to stop by step-over (it will be processed later)
875                elif plugin_manager is not None and main_debugger.has_plugin_line_breaks:
876                    result = plugin_manager.get_breakpoint(main_debugger, self, frame, event, self._args)
877                    if result:
878                        exist_result = True
879                        flag, breakpoint, new_frame, bp_type = result
880
881                if breakpoint:
882                    # ok, hit breakpoint, now, we have to discover if it is a conditional breakpoint
883                    # lets do the conditional stuff here
884                    if stop or exist_result:
885                        eval_result = False
886                        if breakpoint.has_condition:
887                            eval_result = main_debugger.handle_breakpoint_condition(info, breakpoint, new_frame)
888
889                        if breakpoint.expression is not None:
890                            main_debugger.handle_breakpoint_expression(breakpoint, info, new_frame)
891                            if breakpoint.is_logpoint and info.pydev_message is not None and len(info.pydev_message) > 0:
892                                cmd = main_debugger.cmd_factory.make_io_message(info.pydev_message + os.linesep, '1')
893                                main_debugger.writer.add_command(cmd)
894
895                        if breakpoint.has_condition:
896                            if not eval_result:
897                                stop = False
898                        elif breakpoint.is_logpoint:
899                            stop = False
900
901                    if is_call and frame.f_code.co_name in ('<module>', '<lambda>'):
902                        # If we find a call for a module, it means that the module is being imported/executed for the
903                        # first time. In this case we have to ignore this hit as it may later duplicated by a
904                        # line event at the same place (so, if there's a module with a print() in the first line
905                        # the user will hit that line twice, which is not what we want).
906                        #
907                        # As for lambda, as it only has a single statement, it's not interesting to trace
908                        # its call and later its line event as they're usually in the same line.
909
910                        return self.trace_dispatch
911
912                if main_debugger.show_return_values:
913                    if is_return and (
914                            (info.pydev_step_cmd in (CMD_STEP_OVER, CMD_STEP_OVER_MY_CODE, CMD_SMART_STEP_INTO) and (frame.f_back is stop_frame)) or
915                            (info.pydev_step_cmd in (CMD_STEP_RETURN, CMD_STEP_RETURN_MY_CODE) and (frame is stop_frame)) or
916                            (info.pydev_step_cmd in (CMD_STEP_INTO, CMD_STEP_INTO_COROUTINE)) or
917                            (
918                                info.pydev_step_cmd == CMD_STEP_INTO_MY_CODE
919                                and frame.f_back is not None
920                                and not main_debugger.apply_files_filter(frame.f_back, frame.f_back.f_code.co_filename, True)
921                            )
922                        ):
923                        self._show_return_values(frame, arg)
924
925                elif main_debugger.remove_return_values_flag:
926                    try:
927                        self._remove_return_values(main_debugger, frame)
928                    finally:
929                        main_debugger.remove_return_values_flag = False
930
931                if stop:
932                    self.set_suspend(
933                        thread,
934                        stop_reason,
935                        suspend_other_threads=breakpoint and breakpoint.suspend_policy == "ALL",
936                    )
937
938                elif flag and plugin_manager is not None:
939                    result = plugin_manager.suspend(main_debugger, thread, frame, bp_type)
940                    if result:
941                        frame = result
942
943                # if thread has a suspend flag, we suspend with a busy wait
944                if info.pydev_state == STATE_SUSPEND:
945                    self.do_wait_suspend(thread, frame, event, arg)
946                    return self.trace_dispatch
947                else:
948                    if not breakpoint and is_line:
949                        # No stop from anyone and no breakpoint found in line (cache that).
950                        frame_skips_cache[line_cache_key] = 0
951
952            except:
953                pydev_log.exception()
954                raise
955
956            # step handling. We stop when we hit the right frame
957            try:
958                should_skip = 0
959                if pydevd_dont_trace.should_trace_hook is not None:
960                    if self.should_skip == -1:
961                        # I.e.: cache the result on self.should_skip (no need to evaluate the same frame multiple times).
962                        # Note that on a code reload, we won't re-evaluate this because in practice, the frame.f_code
963                        # Which will be handled by this frame is read-only, so, we can cache it safely.
964                        if not pydevd_dont_trace.should_trace_hook(frame, abs_path_canonical_path_and_base[0]):
965                            # -1, 0, 1 to be Cython-friendly
966                            should_skip = self.should_skip = 1
967                        else:
968                            should_skip = self.should_skip = 0
969                    else:
970                        should_skip = self.should_skip
971
972                plugin_stop = False
973                if should_skip:
974                    stop = False
975
976                elif step_cmd in (CMD_STEP_INTO, CMD_STEP_INTO_MY_CODE, CMD_STEP_INTO_COROUTINE):
977                    force_check_project_scope = step_cmd == CMD_STEP_INTO_MY_CODE
978                    if is_line:
979                        if force_check_project_scope or main_debugger.is_files_filter_enabled:
980                            stop = not main_debugger.apply_files_filter(frame, frame.f_code.co_filename, force_check_project_scope)
981                        else:
982                            stop = True
983
984                    elif is_return and frame.f_back is not None:
985                        if main_debugger.get_file_type(frame.f_back) == main_debugger.PYDEV_FILE:
986                            stop = False
987                        else:
988                            if force_check_project_scope or main_debugger.is_files_filter_enabled:
989                                stop = not main_debugger.apply_files_filter(frame.f_back, frame.f_back.f_code.co_filename, force_check_project_scope)
990                                if stop:
991                                    # Prevent stopping in a return to the same location we were initially
992                                    # (i.e.: double-stop at the same place due to some filtering).
993                                    if info.step_in_initial_location == (frame.f_back, frame.f_back.f_lineno):
994                                        stop = False
995                            else:
996                                stop = True
997                    else:
998                        stop = False
999
1000                    if stop:
1001                        if step_cmd == CMD_STEP_INTO_COROUTINE:
1002                            # i.e.: Check if we're stepping into the proper context.
1003                            f = frame
1004                            while f is not None:
1005                                if f is stop_frame:
1006                                    break
1007                                f = f.f_back
1008                            else:
1009                                stop = False
1010
1011                    if plugin_manager is not None:
1012                        result = plugin_manager.cmd_step_into(main_debugger, frame, event, self._args, stop_info, stop)
1013                        if result:
1014                            stop, plugin_stop = result
1015
1016                elif step_cmd in (CMD_STEP_OVER, CMD_STEP_OVER_MY_CODE):
1017                    # Note: when dealing with a step over my code it's the same as a step over (the
1018                    # difference is that when we return from a frame in one we go to regular step
1019                    # into and in the other we go to a step into my code).
1020                    stop = stop_frame is frame and is_line
1021                    # Note: don't stop on a return for step over, only for line events
1022                    # i.e.: don't stop in: (stop_frame is frame.f_back and is_return) as we'd stop twice in that line.
1023
1024                    if plugin_manager is not None:
1025                        result = plugin_manager.cmd_step_over(main_debugger, frame, event, self._args, stop_info, stop)
1026                        if result:
1027                            stop, plugin_stop = result
1028
1029                elif step_cmd == CMD_SMART_STEP_INTO:
1030                    stop = False
1031                    back = frame.f_back
1032                    if stop_frame is frame and is_return:
1033                        # We're exiting the smart step into initial frame (so, we probably didn't find our target).
1034                        stop = True
1035
1036                    elif stop_frame is back and is_line:
1037                        if info.pydev_smart_child_offset != -1:
1038                            # i.e.: in this case, we're not interested in the pause in the parent, rather
1039                            # we're interested in the pause in the child (when the parent is at the proper place).
1040                            stop = False
1041
1042                        else:
1043                            pydev_smart_parent_offset = info.pydev_smart_parent_offset
1044
1045                            pydev_smart_step_into_variants = info.pydev_smart_step_into_variants
1046                            if pydev_smart_parent_offset >= 0 and pydev_smart_step_into_variants:
1047                                # Preferred mode (when the smart step into variants are available
1048                                # and the offset is set).
1049                                stop = get_smart_step_into_variant_from_frame_offset(back.f_lasti, pydev_smart_step_into_variants) is \
1050                                       get_smart_step_into_variant_from_frame_offset(pydev_smart_parent_offset, pydev_smart_step_into_variants)
1051
1052                            else:
1053                                # Only the name/line is available, so, check that.
1054                                curr_func_name = frame.f_code.co_name
1055
1056                                # global context is set with an empty name
1057                                if curr_func_name in ('?', '<module>') or curr_func_name is None:
1058                                    curr_func_name = ''
1059                                if curr_func_name == info.pydev_func_name and stop_frame.f_lineno == info.pydev_next_line:
1060                                    stop = True
1061
1062                        if not stop:
1063                            # In smart step into, if we didn't hit it in this frame once, that'll
1064                            # not be the case next time either, so, disable tracing for this frame.
1065                            return None if is_call else NO_FTRACE
1066
1067                    elif back is not None and stop_frame is back.f_back and is_line:
1068                        # Ok, we have to track 2 stops at this point, the parent and the child offset.
1069                        # This happens when handling a step into which targets a function inside a list comprehension
1070                        # or generator (in which case an intermediary frame is created due to an internal function call).
1071                        pydev_smart_parent_offset = info.pydev_smart_parent_offset
1072                        pydev_smart_child_offset = info.pydev_smart_child_offset
1073                        # print('matched back frame', pydev_smart_parent_offset, pydev_smart_child_offset)
1074                        # print('parent f_lasti', back.f_back.f_lasti)
1075                        # print('child f_lasti', back.f_lasti)
1076                        stop = False
1077                        if pydev_smart_child_offset >= 0 and pydev_smart_child_offset >= 0:
1078                            pydev_smart_step_into_variants = info.pydev_smart_step_into_variants
1079
1080                            if pydev_smart_parent_offset >= 0 and pydev_smart_step_into_variants:
1081                                # Note that we don't really check the parent offset, only the offset of
1082                                # the child (because this is a generator, the parent may have moved forward
1083                                # already -- and that's ok, so, we just check that the parent frame
1084                                # matches in this case).
1085                                smart_step_into_variant = get_smart_step_into_variant_from_frame_offset(pydev_smart_parent_offset, pydev_smart_step_into_variants)
1086                                # print('matched parent offset', pydev_smart_parent_offset)
1087                                # Ok, now, check the child variant
1088                                children_variants = smart_step_into_variant.children_variants
1089                                stop = children_variants and (
1090                                    get_smart_step_into_variant_from_frame_offset(back.f_lasti, children_variants) is \
1091                                    get_smart_step_into_variant_from_frame_offset(pydev_smart_child_offset, children_variants)
1092                                )
1093                                # print('stop at child', stop)
1094
1095                        if not stop:
1096                            # In smart step into, if we didn't hit it in this frame once, that'll
1097                            # not be the case next time either, so, disable tracing for this frame.
1098                            return None if is_call else NO_FTRACE
1099
1100                elif step_cmd in (CMD_STEP_RETURN, CMD_STEP_RETURN_MY_CODE):
1101                    stop = is_return and stop_frame is frame
1102
1103                else:
1104                    stop = False
1105
1106                if stop and step_cmd != -1 and is_return and IS_PY3K and hasattr(frame, "f_back"):
1107                    f_code = getattr(frame.f_back, 'f_code', None)
1108                    if f_code is not None:
1109                        if main_debugger.get_file_type(frame.f_back) == main_debugger.PYDEV_FILE:
1110                            stop = False
1111
1112                if plugin_stop:
1113                    stopped_on_plugin = plugin_manager.stop(main_debugger, frame, event, self._args, stop_info, arg, step_cmd)
1114                elif stop:
1115                    if is_line:
1116                        self.set_suspend(thread, step_cmd, original_step_cmd=info.pydev_original_step_cmd)
1117                        self.do_wait_suspend(thread, frame, event, arg)
1118                    elif is_return:  # return event
1119                        back = frame.f_back
1120                        if back is not None:
1121                            # When we get to the pydevd run function, the debugging has actually finished for the main thread
1122                            # (note that it can still go on for other threads, but for this one, we just make it finish)
1123                            # So, just setting it to None should be OK
1124                            back_absolute_filename, _, base = get_abs_path_real_path_and_base_from_frame(back)
1125                            if (base, back.f_code.co_name) in (DEBUG_START, DEBUG_START_PY3K):
1126                                back = None
1127
1128                            elif base == TRACE_PROPERTY:
1129                                # We dont want to trace the return event of pydevd_traceproperty (custom property for debugging)
1130                                # if we're in a return, we want it to appear to the user in the previous frame!
1131                                return None if is_call else NO_FTRACE
1132
1133                            elif pydevd_dont_trace.should_trace_hook is not None:
1134                                if not pydevd_dont_trace.should_trace_hook(back, back_absolute_filename):
1135                                    # In this case, we'll have to skip the previous one because it shouldn't be traced.
1136                                    # Also, we have to reset the tracing, because if the parent's parent (or some
1137                                    # other parent) has to be traced and it's not currently, we wouldn't stop where
1138                                    # we should anymore (so, a step in/over/return may not stop anywhere if no parent is traced).
1139                                    # Related test: _debugger_case17a.py
1140                                    main_debugger.set_trace_for_frame_and_parents(back)
1141                                    return None if is_call else NO_FTRACE
1142
1143                        if back is not None:
1144                            # if we're in a return, we want it to appear to the user in the previous frame!
1145                            self.set_suspend(thread, step_cmd, original_step_cmd=info.pydev_original_step_cmd)
1146                            self.do_wait_suspend(thread, back, event, arg)
1147                        else:
1148                            # in jython we may not have a back frame
1149                            info.pydev_step_stop = None
1150                            info.pydev_original_step_cmd = -1
1151                            info.pydev_step_cmd = -1
1152                            info.pydev_state = STATE_RUN
1153
1154            except KeyboardInterrupt:
1155                raise
1156            except:
1157                try:
1158                    pydev_log.exception()
1159                    info.pydev_original_step_cmd = -1
1160                    info.pydev_step_cmd = -1
1161                    info.pydev_step_stop = None
1162                except:
1163                    return None if is_call else NO_FTRACE
1164
1165            # if we are quitting, let's stop the tracing
1166            if main_debugger.quitting:
1167                return None if is_call else NO_FTRACE
1168
1169            return self.trace_dispatch
1170        finally:
1171            info.is_tracing -= 1
1172
1173        # end trace_dispatch
1174