예제 #1
0
        def update_name(self):
            tasklet = self.tasklet_weakref()
            if tasklet:
                try:
                    name = tasklet.name
                except AttributeError:
                    if tasklet.is_main:
                        name = 'MainTasklet'
                    else:
                        name = 'Tasklet-%s' % (self._tasklet_id,)

                thread_id = tasklet.thread_id
                for thread in threading.enumerate():
                    if thread.ident == thread_id:
                        if thread.name:
                            thread_name = "of %s" % (thread.name,)
                        else:
                            thread_name = "of Thread-%s" % (thread.name or str(thread_id),)
                        break
                else:
                    # should not happen.
                    thread_name = "of Thread-%s" % (str(thread_id),)
                thread = None

                tid = id(tasklet)
                tasklet = None
            else:
                name = 'Tasklet-%s' % (self._tasklet_id,)
                thread_name = ""
                tid = '-'
            self.tasklet_name = '%s %s (%s)' % (name, thread_name, tid)
def settrace_while_running_if_frame_eval(py_db, trace_func):
    if not py_db.ready_to_run:
        # do it if only debug session is started
        return

    if py_db.frame_eval_func is None:
        return

    threads = threading.enumerate()
    try:
        for t in threads:
            if getattr(t, 'is_pydev_daemon_thread', False):
                continue
            additional_info = None
            try:
                additional_info = t.additional_info
            except AttributeError:
                pass  # that's ok, no info currently set
            if additional_info is None:
                continue

            for frame in additional_info.iter_frames(t):
                py_db.set_trace_for_frame_and_parents(
                    frame, overwrite_prev_trace=True, dispatch_func=trace_func)
            py_db.enable_cache_frames_without_breaks(False)
            # sometimes (when script enters new frames too fast), we can't enable tracing only in the appropriate
            # frame. So, if breakpoint was added during run, we should disable frame evaluation forever.
            py_db.do_not_use_frame_eval = True
    except:
        traceback.print_exc()
def settrace_while_running_if_frame_eval(py_db, trace_func):
    if not py_db.ready_to_run:
        # do it if only debug session is started
        return

    if py_db.frame_eval_func is None:
        return

    threads = threading.enumerate()
    try:
        for t in threads:
            if getattr(t, 'is_pydev_daemon_thread', False):
                continue
            additional_info = None
            try:
                additional_info = t.additional_info
            except AttributeError:
                pass  # that's ok, no info currently set
            if additional_info is None:
                continue

            for frame in additional_info.iter_frames(t):
                py_db.set_trace_for_frame_and_parents(frame, overwrite_prev_trace=True, dispatch_func=trace_func)
            py_db.enable_cache_frames_without_breaks(False)
            # sometimes (when script enters new frames too fast), we can't enable tracing only in the appropriate
            # frame. So, if breakpoint was added during run, we should disable frame evaluation forever.
            py_db.do_not_use_frame_eval = True
    except:
        traceback.print_exc()
예제 #4
0
        def update_name(self):
            tasklet = self.tasklet_weakref()
            if tasklet:
                try:
                    name = tasklet.name
                except AttributeError:
                    if tasklet.is_main:
                        name = 'MainTasklet'
                    else:
                        name = 'Tasklet-%s' % (self._tasklet_id, )

                thread_id = tasklet.thread_id
                for thread in threading.enumerate():
                    if thread.ident == thread_id:
                        if thread.name:
                            thread_name = "of %s" % (thread.name, )
                        else:
                            thread_name = "of Thread-%s" % (thread.name or
                                                            str(thread_id), )
                        break
                else:
                    # should not happen.
                    thread_name = "of Thread-%s" % (str(thread_id), )
                thread = None

                tid = id(tasklet)
                tasklet = None
            else:
                name = 'Tasklet-%s' % (self._tasklet_id, )
                thread_name = ""
                tid = '-'
            self.tasklet_name = '%s %s (%s)' % (name, thread_name, tid)
def dump_threads(stream=None, show_pydevd_threads=True):
    '''
    Helper to dump thread info.
    '''
    if stream is None:
        stream = sys.stderr
    thread_id_to_name_and_is_pydevd_thread = {}
    try:
        for t in threading.enumerate():
            is_pydevd_thread = getattr(t, 'is_pydev_daemon_thread', False)
            thread_id_to_name_and_is_pydevd_thread[t.ident] = (
                '%s  (daemon: %s, pydevd thread: %s)' %
                (t.name, t.daemon, is_pydevd_thread), is_pydevd_thread)
    except:
        pass

    stream.write(
        '===============================================================================\n'
    )
    stream.write('Threads running\n')
    stream.write(
        '================================= Thread Dump =================================\n'
    )
    stream.flush()

    for thread_id, frame in _tid_to_frame_for_dump_threads().items():
        name, is_pydevd_thread = thread_id_to_name_and_is_pydevd_thread.get(
            thread_id, (thread_id, False))
        if not show_pydevd_threads and is_pydevd_thread:
            continue

        stream.write(
            '\n-------------------------------------------------------------------------------\n'
        )
        stream.write(" Thread %s" % (name, ))
        stream.write('\n\n')

        for i, (filename, lineno, name,
                line) in enumerate(traceback.extract_stack(frame)):

            stream.write(' File "%s", line %d, in %s\n' %
                         (filename, lineno, name))
            if line:
                stream.write("   %s\n" % (line.strip()))

            if i == 0 and 'self' in frame.f_locals:
                stream.write('   self: ')
                try:
                    stream.write(str(frame.f_locals['self']))
                except:
                    stream.write('Unable to get str of: %s' %
                                 (type(frame.f_locals['self']), ))
                stream.write('\n')
        stream.flush()

    stream.write(
        '\n=============================== END Thread Dump ==============================='
    )
    stream.flush()
예제 #6
0
def get_main_thread():
    if hasattr(threading, 'main_thread'):
        return threading.main_thread()
    else:
        for t in threading.enumerate():
            if isinstance(t, threading._MainThread):
                return t
    return None
def get_main_thread():
    if hasattr(threading, 'main_thread'):
        return threading.main_thread()
    else:
        for t in threading.enumerate():
            if isinstance(t, threading._MainThread):
                return t
    return None
예제 #8
0
def dump_threads(stream=None):
    '''
    Helper to dump thread info.
    '''
    if stream is None:
        stream = sys.stderr
    thread_id_to_name = {}
    try:
        for t in threading.enumerate():
            thread_id_to_name[
                t.ident] = '%s  (daemon: %s, pydevd thread: %s)' % (
                    t.name, t.daemon,
                    getattr(t, 'is_pydev_daemon_thread', False))
    except:
        pass

    from _pydevd_bundle.pydevd_additional_thread_info_regular import _current_frames

    stream.write(
        '===============================================================================\n'
    )
    stream.write('Threads running\n')
    stream.write(
        '================================= Thread Dump =================================\n'
    )
    stream.flush()

    for thread_id, stack in _current_frames().items():
        stream.write(
            '\n-------------------------------------------------------------------------------\n'
        )
        stream.write(" Thread %s" %
                     thread_id_to_name.get(thread_id, thread_id))
        stream.write('\n\n')

        for i, (filename, lineno, name,
                line) in enumerate(traceback.extract_stack(stack)):

            stream.write(' File "%s", line %d, in %s\n' %
                         (filename, lineno, name))
            if line:
                stream.write("   %s\n" % (line.strip()))

            if i == 0 and 'self' in stack.f_locals:
                stream.write('   self: ')
                try:
                    stream.write(str(stack.f_locals['self']))
                except:
                    stream.write('Unable to get str of: %s' %
                                 (type(stack.f_locals['self']), ))
                stream.write('\n')
        stream.flush()

    stream.write(
        '\n=============================== END Thread Dump ==============================='
    )
    stream.flush()
예제 #9
0
def pydevd_find_thread_by_id(thread_id):
    try:
        threads = threading.enumerate()
        for i in threads:
            tid = get_thread_id(i)
            if thread_id == tid or thread_id.endswith('|' + tid):
                return i

        # This can happen when a request comes for a thread which was previously removed.
        pydev_log.info("Could not find thread %s.", thread_id)
        pydev_log.info("Available: %s.",
                       ([get_thread_id(t) for t in threads], ))
    except:
        pydev_log.exception()

    return None
예제 #10
0
def pydevd_find_thread_by_id(thread_id):
    try:
        # there was a deadlock here when I did not remove the tracing function when thread was dead
        threads = threading.enumerate()
        for i in threads:
            tid = get_thread_id(i)
            if thread_id == tid or thread_id.endswith('|' + tid):
                return i

        # This can happen when a request comes for a thread which was previously removed.
        pydevd_log(1, "Could not find thread %s\n" % (thread_id,))
        pydevd_log(1, "Available: %s\n" % ([get_thread_id(t) for t in threads],))
    except:
        traceback.print_exc()

    return None
예제 #11
0
    def update_name(self):
        tasklet = self.tasklet_weakref()
        if tasklet:
            if tasklet.blocked:
                state = 'blocked'
            elif tasklet.paused:
                state = 'paused'
            elif tasklet.scheduled:
                state = 'scheduled'
            else:
                state = '<UNEXPECTED>'

            try:
                name = tasklet.name
            except AttributeError:
                if tasklet.is_main:
                    name = 'MainTasklet'
                else:
                    name = 'Tasklet-%s' % (self._tasklet_id, )

            thread_id = tasklet.thread_id
            if thread_id != -1:
                for thread in threading.enumerate():
                    if thread.ident == thread_id:
                        if thread.name:
                            thread_name = "of %s" % (thread.name, )
                        else:
                            thread_name = "of Thread-%s" % (thread.name or
                                                            str(thread_id), )
                        break
                else:
                    # should not happen.
                    thread_name = "of Thread-%s" % (str(thread_id), )
                thread = None
            else:
                # tasklet is no longer bound to a thread, because its thread ended
                thread_name = "without thread"

            tid = id(tasklet)
            tasklet = None
        else:
            state = 'dead'
            name = 'Tasklet-%s' % (self._tasklet_id, )
            thread_name = ""
            tid = '-'
        self.tasklet_name = '%s %s %s (%s)' % (state, name, thread_name, tid)
예제 #12
0
    def update_name(self):
        tasklet = self.tasklet_weakref()
        if tasklet:
            if tasklet.blocked:
                state = 'blocked'
            elif tasklet.paused:
                state = 'paused'
            elif tasklet.scheduled:
                state = 'scheduled'
            else:
                state = '<UNEXPECTED>'

            try:
                name = tasklet.name
            except AttributeError:
                if tasklet.is_main:
                    name = 'MainTasklet'
                else:
                    name = 'Tasklet-%s' % (self._tasklet_id,)

            thread_id = tasklet.thread_id
            if thread_id != -1:
                for thread in threading.enumerate():
                    if thread.ident == thread_id:
                        if thread.name:
                            thread_name = "of %s" % (thread.name,)
                        else:
                            thread_name = "of Thread-%s" % (thread.name or str(thread_id),)
                        break
                else:
                    # should not happen.
                    thread_name = "of Thread-%s" % (str(thread_id),)
                thread = None
            else:
                # tasklet is no longer bound to a thread, because its thread ended
                thread_name = "without thread"

            tid = id(tasklet)
            tasklet = None
        else:
            state = 'dead'
            name = 'Tasklet-%s' % (self._tasklet_id,)
            thread_name = ""
            tid = '-'
        self.tasklet_name = '%s %s %s (%s)' % (state, name, thread_name, tid)
예제 #13
0
def dump_threads(stream=None):
    '''
    Helper to dump thread info.
    '''
    if stream is None:
        stream = sys.stderr
    thread_id_to_name = {}
    try:
        for t in threading.enumerate():
            thread_id_to_name[t.ident] = '%s  (daemon: %s, pydevd thread: %s)' % (
                t.name, t.daemon, getattr(t, 'is_pydev_daemon_thread', False))
    except:
        pass

    from _pydevd_bundle.pydevd_additional_thread_info_regular import _current_frames

    stream.write('===============================================================================\n')
    stream.write('Threads running\n')
    stream.write('================================= Thread Dump =================================\n')
    stream.flush()

    for thread_id, stack in _current_frames().items():
        stream.write('\n-------------------------------------------------------------------------------\n')
        stream.write(" Thread %s" % thread_id_to_name.get(thread_id, thread_id))
        stream.write('\n\n')

        for i, (filename, lineno, name, line) in enumerate(traceback.extract_stack(stack)):

            stream.write(' File "%s", line %d, in %s\n' % (filename, lineno, name))
            if line:
                stream.write("   %s\n" % (line.strip()))

            if i == 0 and 'self' in stack.f_locals:
                stream.write('   self: ')
                try:
                    stream.write(str(stack.f_locals['self']))
                except:
                    stream.write('Unable to get str of: %s' % (type(stack.f_locals['self']),))
                stream.write('\n')
        stream.flush()

    stream.write('\n=============================== END Thread Dump ===============================')
    stream.flush()
def get_non_pydevd_threads():
    threads = threading.enumerate()
    return [
        t for t in threads
        if t and not getattr(t, 'is_pydev_daemon_thread', False)
    ]
예제 #15
0
def set_trace_to_threads(tracing_func):
    lib = load_python_helper_lib()
    if lib is None:  # This is the case if it's not CPython.
        pydev_log.info(
            'Unable to load helper lib to set tracing to all threads (unsupported python vm).'
        )
        return -1

    pydev_log.info(
        'Successfully Loaded helper lib to set tracing to all threads.')

    ret = 0
    set_trace_func = TracingFunctionHolder._original_tracing or sys.settrace

    # Note: use sys._current_frames() keys to get the thread ids because it'll return
    # thread ids created in C/C++ where there's user code running, unlike the APIs
    # from the threading module which see only threads created through it (unless
    # a call for threading.current_thread() was previously done in that thread,
    # in which case a dummy thread would've been created for it).
    thread_idents = set(sys._current_frames().keys())
    thread_idents = thread_idents.difference(
        # Ignore pydevd threads.
        set(t.ident for t in threading.enumerate()
            if getattr(t, 'pydev_do_not_trace', False)))

    curr_ident = thread.get_ident()
    curr_thread = threading._active.get(curr_ident)

    for thread_ident in thread_idents:
        # If that thread is not available in the threading module we also need to create a
        # dummy thread for it (otherwise it'll be invisible to the debugger).
        if thread_ident not in threading._active:

            class _DummyThread(threading._DummyThread):
                def _set_ident(self):
                    # Note: Hack to set the thread ident that we want.
                    if IS_PY2:
                        self._Thread__ident = thread_ident
                    else:
                        self._ident = thread_ident

            t = _DummyThread()
            # Reset to the base class (don't expose our own version of the class).
            t.__class__ = threading._DummyThread

            with threading._active_limbo_lock:
                # On Py2 it'll put in active getting the current indent, not using the
                # ident that was set, so, we have to update it (should be harmless on Py3
                # so, do it always).
                threading._active[thread_ident] = t
                threading._active[curr_ident] = curr_thread

                if t.ident != thread_ident:
                    # Check if it actually worked.
                    pydev_log.critical(
                        'pydevd: creation of _DummyThread with fixed thread ident did not succeed.'
                    )

        # Some (ptvsd) tests failed because of this, so, leave it always disabled for now.
        # show_debug_info = 1 if DebugInfoHolder.DEBUG_TRACE_LEVEL >= 1 else 0
        show_debug_info = 0

        # Hack to increase _Py_TracingPossible.
        # See comments on py_custom_pyeval_settrace.hpp
        proceed = thread.allocate_lock()
        proceed.acquire()

        def dummy_trace(frame, event, arg):
            return dummy_trace

        def increase_tracing_count():
            SetTrace(dummy_trace)
            proceed.release()

        start_new_thread = pydev_monkey.get_original_start_new_thread(thread)
        start_new_thread(increase_tracing_count, ())
        proceed.acquire()  # Only proceed after the release() is done.
        proceed = None

        result = lib.AttachDebuggerTracing(
            ctypes.c_int(show_debug_info),
            ctypes.py_object(set_trace_func),
            ctypes.py_object(tracing_func),
            ctypes.c_uint(thread_ident),
            ctypes.py_object(None),
        )
        if result != 0:
            pydev_log.info(
                'Unable to set tracing for existing thread. Result: %s',
                result)
            ret = result

    return ret
예제 #16
0
def set_trace_to_threads(tracing_func,
                         thread_idents=None,
                         create_dummy_thread=True):
    assert tracing_func is not None

    ret = 0

    # Note: use sys._current_frames() keys to get the thread ids because it'll return
    # thread ids created in C/C++ where there's user code running, unlike the APIs
    # from the threading module which see only threads created through it (unless
    # a call for threading.current_thread() was previously done in that thread,
    # in which case a dummy thread would've been created for it).
    if thread_idents is None:
        thread_idents = set(sys._current_frames().keys())

        for t in threading.enumerate():
            # PY-44778: ignore pydevd threads and also add any thread that wasn't found on
            # sys._current_frames() as some existing threads may not appear in
            # sys._current_frames() but may be available through the `threading` module.
            if getattr(t, 'pydev_do_not_trace', False):
                thread_idents.discard(t.ident)
            else:
                thread_idents.add(t.ident)

    curr_ident = thread.get_ident()
    curr_thread = threading._active.get(curr_ident)

    if curr_ident in thread_idents and len(thread_idents) != 1:
        # The current thread must be updated first (because we need to set
        # the reference to `curr_thread`).
        thread_idents = list(thread_idents)
        thread_idents.remove(curr_ident)
        thread_idents.insert(0, curr_ident)

    for thread_ident in thread_idents:
        # If that thread is not available in the threading module we also need to create a
        # dummy thread for it (otherwise it'll be invisible to the debugger).
        if create_dummy_thread:
            if thread_ident not in threading._active:

                class _DummyThread(threading._DummyThread):
                    def _set_ident(self):
                        # Note: Hack to set the thread ident that we want.
                        if IS_PY2:
                            self._Thread__ident = thread_ident
                        else:
                            self._ident = thread_ident

                t = _DummyThread()
                # Reset to the base class (don't expose our own version of the class).
                t.__class__ = threading._DummyThread

                if thread_ident == curr_ident:
                    curr_thread = t

                with threading._active_limbo_lock:
                    # On Py2 it'll put in active getting the current indent, not using the
                    # ident that was set, so, we have to update it (should be harmless on Py3
                    # so, do it always).
                    threading._active[thread_ident] = t
                    threading._active[curr_ident] = curr_thread

                    if t.ident != thread_ident:
                        # Check if it actually worked.
                        pydev_log.critical(
                            'pydevd: creation of _DummyThread with fixed thread ident did not succeed.'
                        )

        # Some (ptvsd) tests failed because of this, so, leave it always disabled for now.
        # show_debug_info = 1 if DebugInfoHolder.DEBUG_TRACE_LEVEL >= 1 else 0
        show_debug_info = 0

        # Hack to increase _Py_TracingPossible.
        # See comments on py_custom_pyeval_settrace.hpp
        proceed = thread.allocate_lock()
        proceed.acquire()

        def dummy_trace(frame, event, arg):
            return dummy_trace

        def increase_tracing_count():
            set_trace = TracingFunctionHolder._original_tracing or sys.settrace
            set_trace(dummy_trace)
            proceed.release()

        start_new_thread = pydev_monkey.get_original_start_new_thread(thread)
        start_new_thread(increase_tracing_count, ())
        proceed.acquire()  # Only proceed after the release() is done.
        proceed = None

        # Note: The set_trace_func is not really used anymore in the C side.
        set_trace_func = TracingFunctionHolder._original_tracing or sys.settrace

        lib = _load_python_helper_lib()
        if lib is None:  # This is the case if it's not CPython.
            pydev_log.info(
                'Unable to load helper lib to set tracing to all threads (unsupported python vm).'
            )
            ret = -1
        else:
            try:
                result = lib.AttachDebuggerTracing(
                    ctypes.c_int(show_debug_info),
                    ctypes.py_object(set_trace_func),
                    ctypes.py_object(tracing_func),
                    ctypes.c_uint(thread_ident),
                    ctypes.py_object(None),
                )
            except:
                if DebugInfoHolder.DEBUG_TRACE_LEVEL >= 1:
                    # There is no need to show this unless debug tracing is enabled.
                    pydev_log.exception('Error attaching debugger tracing')
                ret = -1
            else:
                if result != 0:
                    pydev_log.info(
                        'Unable to set tracing for existing thread. Result: %s',
                        result)
                    ret = result

    return ret
예제 #17
0
def set_trace_to_threads(tracing_func):
    lib = load_python_helper_lib()
    if lib is None:  # This is the case if it's not CPython.
        return -1

    if hasattr(sys, 'getswitchinterval'):
        get_interval, set_interval = sys.getswitchinterval, sys.setswitchinterval
    else:
        get_interval, set_interval = sys.getcheckinterval, sys.setcheckinterval

    prev_value = get_interval()
    ret = 0
    try:
        if not IS_PY37_OR_GREATER:
            # Prevent going to any other thread... if we switch the thread during this operation we
            # could potentially corrupt the interpreter.
            # Note: on CPython 3.7 onwards this is not needed (we have a different implementation
            # for setting the tracing for other threads in this case).
            set_interval(2 ** 15)

        set_trace_func = TracingFunctionHolder._original_tracing or sys.settrace

        # Note: use sys._current_frames() keys to get the thread ids because it'll return
        # thread ids created in C/C++ where there's user code running, unlike the APIs
        # from the threading module which see only threads created through it (unless
        # a call for threading.current_thread() was previously done in that thread,
        # in which case a dummy thread would've been created for it).
        thread_idents = set(sys._current_frames().keys())
        thread_idents = thread_idents.difference(
            # Ignore pydevd threads.
            set(t.ident for t in threading.enumerate() if getattr(t, 'pydev_do_not_trace', False))
        )

        curr_ident = thread.get_ident()
        curr_thread = threading._active.get(curr_ident)

        for thread_ident in thread_idents:
            # If that thread is not available in the threading module we also need to create a
            # dummy thread for it (otherwise it'll be invisible to the debugger).
            if thread_ident not in threading._active:

                class _DummyThread(threading._DummyThread):

                    def _set_ident(self):
                        # Note: Hack to set the thread ident that we want.
                        if IS_PY2:
                            self._Thread__ident = thread_ident
                        else:
                            self._ident = thread_ident

                t = _DummyThread()
                # Reset to the base class (don't expose our own version of the class).
                t.__class__ = threading._DummyThread

                with threading._active_limbo_lock:
                    # On Py2 it'll put in active getting the current indent, not using the
                    # ident that was set, so, we have to update it (should be harmless on Py3
                    # so, do it always).
                    threading._active[thread_ident] = t
                    threading._active[curr_ident] = curr_thread

                    if t.ident != thread_ident:
                        # Check if it actually worked.
                        pydev_log.error('pydevd: creation of _DummyThread with fixed thread ident did not succeed.')

            # Some (ptvsd) tests failed because of this, so, leave it always disabled for now.
            # show_debug_info = 1 if DebugInfoHolder.DEBUG_TRACE_LEVEL >= 1 else 0
            show_debug_info = 0

            if IS_PY37_OR_GREATER:
                # Hack to increase _Py_TracingPossible.
                # See comments on py_settrace_37.hpp
                proceed = thread.allocate_lock()
                proceed.acquire()

                def dummy_trace_on_py37(frame, event, arg):
                    return dummy_trace_on_py37

                def increase_tracing_count_on_py37():
                    SetTrace(dummy_trace_on_py37)
                    proceed.release()

                start_new_thread = pydev_monkey.get_original_start_new_thread(thread)
                start_new_thread(increase_tracing_count_on_py37, ())
                proceed.acquire()  # Only proceed after the release() is done.
                proceed = None

            result = lib.AttachDebuggerTracing(
                ctypes.c_int(show_debug_info),
                ctypes.py_object(set_trace_func),
                ctypes.py_object(tracing_func),
                ctypes.c_uint(thread_ident),
                ctypes.py_object(None),
            )
            if result != 0:
                pydev_log.info('Unable to set tracing for existing threads. Result: %s' % result)
                ret = result
    finally:
        if not IS_PY37_OR_GREATER:
            set_interval(prev_value)

    return ret
예제 #18
0
def set_trace_to_threads(tracing_func, target_threads=None):
    if not IS_CPYTHON or ctypes is None or sys.version_info[:2] > (3, 7):
        return -1

    if IS_WINDOWS:
        if IS_64BIT_PROCESS:
            suffix = 'amd64'
        else:
            suffix = 'x86'

        filename = os.path.join(os.path.dirname(__file__),
                                'pydevd_attach_to_process',
                                'attach_%s.dll' % (suffix, ))

    elif IS_LINUX:
        if IS_64BIT_PROCESS:
            suffix = 'amd64'
        else:
            suffix = 'x86'

        filename = os.path.join(os.path.dirname(__file__),
                                'pydevd_attach_to_process',
                                'attach_linux_%s.so' % (suffix, ))

    elif IS_MAC:
        if IS_64BIT_PROCESS:
            suffix = 'x86_64.dylib'
        else:
            suffix = 'x86.dylib'

        filename = os.path.join(os.path.dirname(__file__),
                                'pydevd_attach_to_process',
                                'attach_%s' % (suffix, ))

    else:
        pydev_log.info('Unable to set trace to all threads in platform: %s',
                       sys.platform)
        return -1

    if not os.path.exists(filename):
        pydev_log.critical('Expected: %s to exist.', filename)
        return -1

    try:
        lib = ctypes.cdll.LoadLibrary(filename)
    except:
        pydev_log.exception('Error loading: %s', filename)
        return -1

    if hasattr(sys, 'getswitchinterval'):
        get_interval, set_interval = sys.getswitchinterval, sys.setswitchinterval
    else:
        get_interval, set_interval = sys.getcheckinterval, sys.setcheckinterval

    prev_value = get_interval()
    ret = 0
    try:
        # Prevent going to any other thread... if we switch the thread during this operation we
        # could potentially corrupt the interpreter.
        set_interval(2**15)

        set_trace_func = TracingFunctionHolder._original_tracing or sys.settrace

        if target_threads is None:
            target_threads = list(threading.enumerate())

        for t in target_threads:
            if t and not getattr(t, 'pydev_do_not_trace', None):
                show_debug_info = 0
                result = lib.AttachDebuggerTracing(
                    ctypes.c_int(show_debug_info),
                    ctypes.py_object(set_trace_func),
                    ctypes.py_object(tracing_func), ctypes.c_uint(t.ident))
                if result != 0:
                    pydev_log.info(
                        'Unable to set tracing for existing threads. Result: %s',
                        result)
                    ret = result
    finally:
        set_interval(prev_value)

    return ret
예제 #19
0
def process_net_command(py_db, cmd_id, seq, text):
    '''Processes a command received from the Java side

    @param cmd_id: the id of the command
    @param seq: the sequence of the command
    @param text: the text received in the command

    @note: this method is run as a big switch... after doing some tests, it's not clear whether changing it for
    a dict id --> function call will have better performance result. A simple test with xrange(10000000) showed
    that the gains from having a fast access to what should be executed are lost because of the function call in
    a way that if we had 10 elements in the switch the if..elif are better -- but growing the number of choices
    makes the solution with the dispatch look better -- so, if this gets more than 20-25 choices at some time,
    it may be worth refactoring it (actually, reordering the ifs so that the ones used mostly come before
    probably will give better performance).
    '''
    # print(ID_TO_MEANING[str(cmd_id)], repr(text))

    py_db._main_lock.acquire()
    try:
        try:
            cmd = None
            if cmd_id == CMD_RUN:
                py_db.ready_to_run = True

            elif cmd_id == CMD_SET_PROTOCOL:
                expected = (NetCommand.HTTP_PROTOCOL,
                            NetCommand.QUOTED_LINE_PROTOCOL)
                text = text.strip()
                assert text.strip(
                ) in expected, 'Protocol (%s) should be one of: %s' % (
                    text, expected)

                NetCommand.protocol = text
                cmd = py_db.cmd_factory.make_protocol_set_message(seq)

            elif cmd_id == CMD_VERSION:
                # response is version number
                # ide_os should be 'WINDOWS' or 'UNIX'.

                # Default based on server process (although ideally the IDE should
                # provide it).
                if IS_WINDOWS:
                    ide_os = 'WINDOWS'
                else:
                    ide_os = 'UNIX'

                # Breakpoints can be grouped by 'LINE' or by 'ID'.
                breakpoints_by = 'LINE'

                splitted = text.split('\t')
                if len(splitted) == 1:
                    _local_version = splitted

                elif len(splitted) == 2:
                    _local_version, ide_os = splitted

                elif len(splitted) == 3:
                    _local_version, ide_os, breakpoints_by = splitted

                if breakpoints_by == 'ID':
                    py_db._set_breakpoints_with_id = True
                else:
                    py_db._set_breakpoints_with_id = False

                pydevd_file_utils.set_ide_os(ide_os)

                cmd = py_db.cmd_factory.make_version_message(seq)

            elif cmd_id == CMD_LIST_THREADS:
                # response is a list of threads
                cmd = py_db.cmd_factory.make_list_threads_message(seq)

            elif cmd_id == CMD_GET_THREAD_STACK:
                thread_id = text

                t = pydevd_find_thread_by_id(thread_id)
                frame = None
                if t and not getattr(t, 'pydev_do_not_trace', None):
                    additional_info = set_additional_thread_info(t)
                    frame = additional_info.get_topmost_frame(t)
                try:
                    cmd = py_db.cmd_factory.make_get_thread_stack_message(
                        seq, thread_id, frame)
                finally:
                    frame = None
                    t = None

            elif cmd_id == CMD_THREAD_KILL:
                int_cmd = InternalTerminateThread(text)
                py_db.post_internal_command(int_cmd, text)

            elif cmd_id == CMD_THREAD_SUSPEND:
                # Yes, thread suspend is done at this point, not through an internal command.
                threads = []
                if text.strip() == '*':
                    threads = threading.enumerate()

                elif text.startswith('__frame__:'):
                    sys.stderr.write("Can't suspend tasklet: %s\n" % (text, ))

                else:
                    threads = [pydevd_find_thread_by_id(text)]

                for t in threads:
                    if t and not getattr(t, 'pydev_do_not_trace', None):
                        additional_info = set_additional_thread_info(t)
                        frame = additional_info.get_topmost_frame(t)
                        if frame is not None:
                            try:
                                py_db.set_trace_for_frame_and_parents(frame)
                            finally:
                                frame = None

                        py_db.set_suspend(t, CMD_THREAD_SUSPEND)

            elif cmd_id == CMD_THREAD_RUN:
                threads = []
                if text.strip() == '*':
                    threads = threading.enumerate()

                elif text.startswith('__frame__:'):
                    sys.stderr.write("Can't make tasklet run: %s\n" % (text, ))

                else:
                    threads = [pydevd_find_thread_by_id(text)]

                for t in threads:
                    if t and not getattr(t, 'pydev_do_not_trace', None):
                        additional_info = set_additional_thread_info(t)
                        additional_info.pydev_step_cmd = -1
                        additional_info.pydev_step_stop = None
                        additional_info.pydev_state = STATE_RUN

            elif cmd_id == CMD_STEP_INTO or cmd_id == CMD_STEP_OVER or cmd_id == CMD_STEP_RETURN or \
                    cmd_id == CMD_STEP_INTO_MY_CODE:
                # we received some command to make a single step
                t = pydevd_find_thread_by_id(text)
                if t:
                    thread_id = get_thread_id(t)
                    int_cmd = InternalStepThread(thread_id, cmd_id)
                    py_db.post_internal_command(int_cmd, thread_id)

                elif text.startswith('__frame__:'):
                    sys.stderr.write("Can't make tasklet step command: %s\n" %
                                     (text, ))

            elif cmd_id == CMD_RUN_TO_LINE or cmd_id == CMD_SET_NEXT_STATEMENT or cmd_id == CMD_SMART_STEP_INTO:
                # we received some command to make a single step
                thread_id, line, func_name = text.split('\t', 2)
                t = pydevd_find_thread_by_id(thread_id)
                if t:
                    int_cmd = InternalSetNextStatementThread(
                        thread_id, cmd_id, line, func_name)
                    py_db.post_internal_command(int_cmd, thread_id)
                elif thread_id.startswith('__frame__:'):
                    sys.stderr.write(
                        "Can't set next statement in tasklet: %s\n" %
                        (thread_id, ))

            elif cmd_id == CMD_RELOAD_CODE:
                # we received some command to make a reload of a module
                module_name = text.strip()

                thread_id = '*'  # Any thread

                # Note: not going for the main thread because in this case it'd only do the load
                # when we stopped on a breakpoint.
                # for tid, t in py_db._running_thread_ids.items(): #Iterate in copy
                #    thread_name = t.getName()
                #
                #    print thread_name, get_thread_id(t)
                #    #Note: if possible, try to reload on the main thread
                #    if thread_name == 'MainThread':
                #        thread_id = tid

                int_cmd = ReloadCodeCommand(module_name, thread_id)
                py_db.post_internal_command(int_cmd, thread_id)

            elif cmd_id == CMD_CHANGE_VARIABLE:
                # the text is: thread\tstackframe\tFRAME|GLOBAL\tattribute_to_change\tvalue_to_change
                try:
                    thread_id, frame_id, scope, attr_and_value = text.split(
                        '\t', 3)

                    tab_index = attr_and_value.rindex('\t')
                    attr = attr_and_value[0:tab_index].replace('\t', '.')
                    value = attr_and_value[tab_index + 1:]
                    int_cmd = InternalChangeVariable(seq, thread_id, frame_id,
                                                     scope, attr, value)
                    py_db.post_internal_command(int_cmd, thread_id)

                except:
                    traceback.print_exc()

            elif cmd_id == CMD_GET_VARIABLE:
                # we received some command to get a variable
                # the text is: thread_id\tframe_id\tFRAME|GLOBAL\tattributes*
                try:
                    thread_id, frame_id, scopeattrs = text.split('\t', 2)

                    if scopeattrs.find(
                            '\t') != -1:  # there are attributes beyond scope
                        scope, attrs = scopeattrs.split('\t', 1)
                    else:
                        scope, attrs = (scopeattrs, None)

                    int_cmd = InternalGetVariable(seq, thread_id, frame_id,
                                                  scope, attrs)
                    py_db.post_internal_command(int_cmd, thread_id)

                except:
                    traceback.print_exc()

            elif cmd_id == CMD_GET_ARRAY:
                # we received some command to get an array variable
                # the text is: thread_id\tframe_id\tFRAME|GLOBAL\tname\ttemp\troffs\tcoffs\trows\tcols\tformat
                try:
                    roffset, coffset, rows, cols, format, thread_id, frame_id, scopeattrs = text.split(
                        '\t', 7)

                    if scopeattrs.find(
                            '\t') != -1:  # there are attributes beyond scope
                        scope, attrs = scopeattrs.split('\t', 1)
                    else:
                        scope, attrs = (scopeattrs, None)

                    int_cmd = InternalGetArray(seq, roffset, coffset, rows,
                                               cols, format, thread_id,
                                               frame_id, scope, attrs)
                    py_db.post_internal_command(int_cmd, thread_id)

                except:
                    traceback.print_exc()

            elif cmd_id == CMD_SHOW_RETURN_VALUES:
                try:
                    show_return_values = text.split('\t')[1]
                    if int(show_return_values) == 1:
                        py_db.show_return_values = True
                    else:
                        if py_db.show_return_values:
                            # We should remove saved return values
                            py_db.remove_return_values_flag = True
                        py_db.show_return_values = False
                    pydev_log.debug("Show return values: %s\n" %
                                    py_db.show_return_values)
                except:
                    traceback.print_exc()

            elif cmd_id == CMD_LOAD_FULL_VALUE:
                try:
                    thread_id, frame_id, scopeattrs = text.split('\t', 2)
                    vars = scopeattrs.split(NEXT_VALUE_SEPARATOR)

                    int_cmd = InternalLoadFullValue(seq, thread_id, frame_id,
                                                    vars)
                    py_db.post_internal_command(int_cmd, thread_id)
                except:
                    traceback.print_exc()

            elif cmd_id == CMD_GET_COMPLETIONS:
                # we received some command to get a variable
                # the text is: thread_id\tframe_id\tactivation token
                try:
                    thread_id, frame_id, scope, act_tok = text.split('\t', 3)

                    int_cmd = InternalGetCompletions(seq, thread_id, frame_id,
                                                     act_tok)
                    py_db.post_internal_command(int_cmd, thread_id)

                except:
                    traceback.print_exc()
            elif cmd_id == CMD_GET_DESCRIPTION:
                try:

                    thread_id, frame_id, expression = text.split('\t', 2)
                    int_cmd = InternalGetDescription(seq, thread_id, frame_id,
                                                     expression)
                    py_db.post_internal_command(int_cmd, thread_id)
                except:
                    traceback.print_exc()

            elif cmd_id == CMD_GET_FRAME:
                thread_id, frame_id, scope = text.split('\t', 2)

                int_cmd = InternalGetFrame(seq, thread_id, frame_id)
                py_db.post_internal_command(int_cmd, thread_id)

            elif cmd_id == CMD_SET_BREAK:
                # func name: 'None': match anything. Empty: match global, specified: only method context.
                # command to add some breakpoint.
                # text is file\tline. Add to breakpoints dictionary
                suspend_policy = "NONE"  # Can be 'NONE' or 'ALL'
                is_logpoint = False
                hit_condition = None
                if py_db._set_breakpoints_with_id:
                    try:
                        try:
                            breakpoint_id, type, file, line, func_name, condition, expression, hit_condition, is_logpoint, suspend_policy = text.split(
                                '\t', 9)
                        except ValueError:  # not enough values to unpack
                            # No suspend_policy passed (use default).
                            breakpoint_id, type, file, line, func_name, condition, expression, hit_condition, is_logpoint = text.split(
                                '\t', 8)
                        is_logpoint = is_logpoint == 'True'
                    except ValueError:  # not enough values to unpack
                        breakpoint_id, type, file, line, func_name, condition, expression = text.split(
                            '\t', 6)

                    breakpoint_id = int(breakpoint_id)
                    line = int(line)

                    # We must restore new lines and tabs as done in
                    # AbstractDebugTarget.breakpointAdded
                    condition = condition.replace("@_@NEW_LINE_CHAR@_@", '\n').\
                        replace("@_@TAB_CHAR@_@", '\t').strip()

                    expression = expression.replace("@_@NEW_LINE_CHAR@_@", '\n').\
                        replace("@_@TAB_CHAR@_@", '\t').strip()
                else:
                    # Note: this else should be removed after PyCharm migrates to setting
                    # breakpoints by id (and ideally also provides func_name).
                    type, file, line, func_name, suspend_policy, condition, expression = text.split(
                        '\t', 6)
                    # If we don't have an id given for each breakpoint, consider
                    # the id to be the line.
                    breakpoint_id = line = int(line)

                    condition = condition.replace("@_@NEW_LINE_CHAR@_@", '\n'). \
                        replace("@_@TAB_CHAR@_@", '\t').strip()

                    expression = expression.replace("@_@NEW_LINE_CHAR@_@", '\n'). \
                        replace("@_@TAB_CHAR@_@", '\t').strip()

                if not IS_PY3K:  # In Python 3, the frame object will have unicode for the file, whereas on python 2 it has a byte-array encoded with the filesystem encoding.
                    file = file.encode(file_system_encoding)

                file = pydevd_file_utils.norm_file_to_server(file)

                if not pydevd_file_utils.exists(file):
                    sys.stderr.write('pydev debugger: warning: trying to add breakpoint'\
                        ' to file that does not exist: %s (will have no effect)\n' % (file,))
                    sys.stderr.flush()

                if condition is not None and (len(condition) <= 0
                                              or condition == "None"):
                    condition = None

                if expression is not None and (len(expression) <= 0
                                               or expression == "None"):
                    expression = None

                if hit_condition is not None and (len(hit_condition) <= 0
                                                  or hit_condition == "None"):
                    hit_condition = None

                if type == 'python-line':
                    breakpoint = LineBreakpoint(line,
                                                condition,
                                                func_name,
                                                expression,
                                                suspend_policy,
                                                hit_condition=hit_condition,
                                                is_logpoint=is_logpoint)
                    breakpoints = py_db.breakpoints
                    file_to_id_to_breakpoint = py_db.file_to_id_to_line_breakpoint
                    supported_type = True
                else:
                    result = None
                    plugin = py_db.get_plugin_lazy_init()
                    if plugin is not None:
                        result = plugin.add_breakpoint(
                            'add_line_breakpoint',
                            py_db,
                            type,
                            file,
                            line,
                            condition,
                            expression,
                            func_name,
                            hit_condition=hit_condition,
                            is_logpoint=is_logpoint)
                    if result is not None:
                        supported_type = True
                        breakpoint, breakpoints = result
                        file_to_id_to_breakpoint = py_db.file_to_id_to_plugin_breakpoint
                    else:
                        supported_type = False

                if not supported_type:
                    raise NameError(type)

                if DebugInfoHolder.DEBUG_TRACE_BREAKPOINTS > 0:
                    pydev_log.debug(
                        'Added breakpoint:%s - line:%s - func_name:%s\n' %
                        (file, line, func_name.encode('utf-8')))
                    sys.stderr.flush()

                if file in file_to_id_to_breakpoint:
                    id_to_pybreakpoint = file_to_id_to_breakpoint[file]
                else:
                    id_to_pybreakpoint = file_to_id_to_breakpoint[file] = {}

                id_to_pybreakpoint[breakpoint_id] = breakpoint
                py_db.consolidate_breakpoints(file, id_to_pybreakpoint,
                                              breakpoints)
                if py_db.plugin is not None:
                    py_db.has_plugin_line_breaks = py_db.plugin.has_line_breaks(
                    )

                py_db.set_tracing_for_untraced_contexts_if_not_frame_eval()
                py_db.enable_tracing_in_frames_while_running_if_frame_eval()

            elif cmd_id == CMD_REMOVE_BREAK:
                #command to remove some breakpoint
                #text is type\file\tid. Remove from breakpoints dictionary
                breakpoint_type, file, breakpoint_id = text.split('\t', 2)

                if not IS_PY3K:  # In Python 3, the frame object will have unicode for the file, whereas on python 2 it has a byte-array encoded with the filesystem encoding.
                    file = file.encode(file_system_encoding)

                file = pydevd_file_utils.norm_file_to_server(file)

                try:
                    breakpoint_id = int(breakpoint_id)
                except ValueError:
                    pydev_log.error(
                        'Error removing breakpoint. Expected breakpoint_id to be an int. Found: %s'
                        % (breakpoint_id, ))

                else:
                    file_to_id_to_breakpoint = None
                    if breakpoint_type == 'python-line':
                        breakpoints = py_db.breakpoints
                        file_to_id_to_breakpoint = py_db.file_to_id_to_line_breakpoint
                    elif py_db.get_plugin_lazy_init() is not None:
                        result = py_db.plugin.get_breakpoints(
                            py_db, breakpoint_type)
                        if result is not None:
                            file_to_id_to_breakpoint = py_db.file_to_id_to_plugin_breakpoint
                            breakpoints = result

                    if file_to_id_to_breakpoint is None:
                        pydev_log.error(
                            'Error removing breakpoint. Cant handle breakpoint of type %s'
                            % breakpoint_type)
                    else:
                        try:
                            id_to_pybreakpoint = file_to_id_to_breakpoint.get(
                                file, {})
                            if DebugInfoHolder.DEBUG_TRACE_BREAKPOINTS > 0:
                                existing = id_to_pybreakpoint[breakpoint_id]
                                sys.stderr.write(
                                    'Removed breakpoint:%s - line:%s - func_name:%s (id: %s)\n'
                                    % (file, existing.line,
                                       existing.func_name.encode('utf-8'),
                                       breakpoint_id))

                            del id_to_pybreakpoint[breakpoint_id]
                            py_db.consolidate_breakpoints(
                                file, id_to_pybreakpoint, breakpoints)
                            if py_db.plugin is not None:
                                py_db.has_plugin_line_breaks = py_db.plugin.has_line_breaks(
                                )

                        except KeyError:
                            pydev_log.error(
                                "Error removing breakpoint: Breakpoint id not found: %s id: %s. Available ids: %s\n"
                                % (file, breakpoint_id,
                                   dict_keys(id_to_pybreakpoint)))

            elif cmd_id == CMD_EVALUATE_EXPRESSION or cmd_id == CMD_EXEC_EXPRESSION:
                #command to evaluate the given expression
                #text is: thread\tstackframe\tLOCAL\texpression
                temp_name = ""
                try:
                    thread_id, frame_id, scope, expression, trim, temp_name = text.split(
                        '\t', 5)
                except ValueError:
                    thread_id, frame_id, scope, expression, trim = text.split(
                        '\t', 4)
                int_cmd = InternalEvaluateExpression(
                    seq, thread_id, frame_id, expression,
                    cmd_id == CMD_EXEC_EXPRESSION,
                    int(trim) == 1, temp_name)
                py_db.post_internal_command(int_cmd, thread_id)

            elif cmd_id == CMD_CONSOLE_EXEC:
                #command to exec expression in console, in case expression is only partially valid 'False' is returned
                #text is: thread\tstackframe\tLOCAL\texpression

                thread_id, frame_id, scope, expression = text.split('\t', 3)

                int_cmd = InternalConsoleExec(seq, thread_id, frame_id,
                                              expression)
                py_db.post_internal_command(int_cmd, thread_id)

            elif cmd_id == CMD_SET_PY_EXCEPTION:
                # Command which receives set of exceptions on which user wants to break the debugger
                # text is:
                #
                # break_on_uncaught;
                # break_on_caught;
                # skip_on_exceptions_thrown_in_same_context;
                # ignore_exceptions_thrown_in_lines_with_ignore_exception;
                # ignore_libraries;
                # TypeError;ImportError;zipimport.ZipImportError;
                #
                # i.e.: true;true;true;true;true;TypeError;ImportError;zipimport.ZipImportError;
                #
                # This API is optional and works 'in bulk' -- it's possible
                # to get finer-grained control with CMD_ADD_EXCEPTION_BREAK/CMD_REMOVE_EXCEPTION_BREAK
                # which allows setting caught/uncaught per exception.
                splitted = text.split(';')
                py_db.break_on_uncaught_exceptions = {}
                py_db.break_on_caught_exceptions = {}
                added = []
                if len(splitted) >= 5:
                    if splitted[0] == 'true':
                        break_on_uncaught = True
                    else:
                        break_on_uncaught = False

                    if splitted[1] == 'true':
                        break_on_caught = True
                    else:
                        break_on_caught = False

                    if splitted[2] == 'true':
                        py_db.skip_on_exceptions_thrown_in_same_context = True
                    else:
                        py_db.skip_on_exceptions_thrown_in_same_context = False

                    if splitted[3] == 'true':
                        py_db.ignore_exceptions_thrown_in_lines_with_ignore_exception = True
                    else:
                        py_db.ignore_exceptions_thrown_in_lines_with_ignore_exception = False

                    if splitted[4] == 'true':
                        ignore_libraries = True
                    else:
                        ignore_libraries = False

                    for exception_type in splitted[5:]:
                        exception_type = exception_type.strip()
                        if not exception_type:
                            continue

                        exception_breakpoint = py_db.add_break_on_exception(
                            exception_type,
                            condition=None,
                            expression=None,
                            notify_on_handled_exceptions=break_on_caught,
                            notify_on_unhandled_exceptions=break_on_uncaught,
                            notify_on_first_raise_only=True,
                            ignore_libraries=ignore_libraries,
                        )
                        if exception_breakpoint is None:
                            continue
                        added.append(exception_breakpoint)

                    py_db.enable_tracing_in_frames_while_running_if_frame_eval(
                    )
                    py_db.set_tracing_for_untraced_contexts_if_not_frame_eval()

                else:
                    sys.stderr.write(
                        "Error when setting exception list. Received: %s\n" %
                        (text, ))

            elif cmd_id == CMD_GET_FILE_CONTENTS:

                if not IS_PY3K:  # In Python 3, the frame object will have unicode for the file, whereas on python 2 it has a byte-array encoded with the filesystem encoding.
                    text = text.encode(file_system_encoding)

                if os.path.exists(text):
                    f = open(text, 'r')
                    try:
                        source = f.read()
                    finally:
                        f.close()
                    cmd = py_db.cmd_factory.make_get_file_contents(seq, source)

            elif cmd_id == CMD_SET_PROPERTY_TRACE:
                # Command which receives whether to trace property getter/setter/deleter
                # text is feature_state(true/false);disable_getter/disable_setter/disable_deleter
                if text != "":
                    splitted = text.split(';')
                    if len(splitted) >= 3:
                        if py_db.disable_property_trace is False and splitted[
                                0] == 'true':
                            # Replacing property by custom property only when the debugger starts
                            pydevd_traceproperty.replace_builtin_property()
                            py_db.disable_property_trace = True
                        # Enable/Disable tracing of the property getter
                        if splitted[1] == 'true':
                            py_db.disable_property_getter_trace = True
                        else:
                            py_db.disable_property_getter_trace = False
                        # Enable/Disable tracing of the property setter
                        if splitted[2] == 'true':
                            py_db.disable_property_setter_trace = True
                        else:
                            py_db.disable_property_setter_trace = False
                        # Enable/Disable tracing of the property deleter
                        if splitted[3] == 'true':
                            py_db.disable_property_deleter_trace = True
                        else:
                            py_db.disable_property_deleter_trace = False
                else:
                    # User hasn't configured any settings for property tracing
                    pass

            elif cmd_id == CMD_ADD_EXCEPTION_BREAK:
                # Note that this message has some idiosyncrasies...
                #
                # notify_on_handled_exceptions can be 0, 1 or 2
                # 0 means we should not stop on handled exceptions.
                # 1 means we should stop on handled exceptions showing it on all frames where the exception passes.
                # 2 means we should stop on handled exceptions but we should only notify about it once.
                #
                # To ignore_libraries properly, besides setting ignore_libraries to 1, the IDE_PROJECT_ROOTS environment
                # variable must be set (so, we'll ignore anything not below IDE_PROJECT_ROOTS) -- this is not ideal as
                # the environment variable may not be properly set if it didn't start from the debugger (we should
                # create a custom message for that).
                #
                # There are 2 global settings which can only be set in CMD_SET_PY_EXCEPTION. Namely:
                #
                # py_db.skip_on_exceptions_thrown_in_same_context
                # - If True, we should only show the exception in a caller, not where it was first raised.
                #
                # py_db.ignore_exceptions_thrown_in_lines_with_ignore_exception
                # - If True exceptions thrown in lines with '@IgnoreException' will not be shown.

                condition = ""
                expression = ""
                if text.find('\t') != -1:
                    try:
                        exception, condition, expression, notify_on_handled_exceptions, notify_on_unhandled_exceptions, ignore_libraries = text.split(
                            '\t', 5)
                    except:
                        exception, notify_on_handled_exceptions, notify_on_unhandled_exceptions, ignore_libraries = text.split(
                            '\t', 3)
                else:
                    exception, notify_on_handled_exceptions, notify_on_unhandled_exceptions, ignore_libraries = text, 0, 0, 0

                condition = condition.replace("@_@NEW_LINE_CHAR@_@",
                                              '\n').replace(
                                                  "@_@TAB_CHAR@_@",
                                                  '\t').strip()

                if condition is not None and (len(condition) == 0
                                              or condition == "None"):
                    condition = None

                expression = expression.replace("@_@NEW_LINE_CHAR@_@",
                                                '\n').replace(
                                                    "@_@TAB_CHAR@_@",
                                                    '\t').strip()

                if expression is not None and (len(expression) == 0
                                               or expression == "None"):
                    expression = None

                if exception.find('-') != -1:
                    breakpoint_type, exception = exception.split('-')
                else:
                    breakpoint_type = 'python'

                if breakpoint_type == 'python':
                    exception_breakpoint = py_db.add_break_on_exception(
                        exception,
                        condition=condition,
                        expression=expression,
                        notify_on_handled_exceptions=int(
                            notify_on_handled_exceptions) > 0,
                        notify_on_unhandled_exceptions=int(
                            notify_on_unhandled_exceptions) == 1,
                        notify_on_first_raise_only=int(
                            notify_on_handled_exceptions) == 2,
                        ignore_libraries=int(ignore_libraries) > 0)

                    if exception_breakpoint is not None:
                        py_db.enable_tracing_in_frames_while_running_if_frame_eval(
                        )
                        py_db.set_tracing_for_untraced_contexts_if_not_frame_eval(
                        )
                else:
                    supported_type = False
                    plugin = py_db.get_plugin_lazy_init()
                    if plugin is not None:
                        supported_type = plugin.add_breakpoint(
                            'add_exception_breakpoint', py_db, breakpoint_type,
                            exception)

                    if supported_type:
                        py_db.has_plugin_exception_breaks = py_db.plugin.has_exception_breaks(
                        )
                        py_db.enable_tracing_in_frames_while_running_if_frame_eval(
                        )
                    else:
                        raise NameError(breakpoint_type)

            elif cmd_id == CMD_REMOVE_EXCEPTION_BREAK:
                exception = text
                if exception.find('-') != -1:
                    exception_type, exception = exception.split('-')
                else:
                    exception_type = 'python'

                if exception_type == 'python':
                    try:
                        cp = py_db.break_on_uncaught_exceptions.copy()
                        cp.pop(exception, None)
                        py_db.break_on_uncaught_exceptions = cp

                        cp = py_db.break_on_caught_exceptions.copy()
                        cp.pop(exception, None)
                        py_db.break_on_caught_exceptions = cp
                    except:
                        pydev_log.debug("Error while removing exception %s" %
                                        sys.exc_info()[0])
                    py_db.set_tracing_for_untraced_contexts_if_not_frame_eval()
                else:
                    supported_type = False

                    # I.e.: no need to initialize lazy (if we didn't have it in the first place, we can't remove
                    # anything from it anyways).
                    plugin = py_db.plugin
                    if plugin is not None:
                        supported_type = plugin.remove_exception_breakpoint(
                            py_db, exception_type, exception)

                    if supported_type:
                        py_db.has_plugin_exception_breaks = py_db.plugin.has_exception_breaks(
                        )
                    else:
                        raise NameError(exception_type)
                if len(py_db.break_on_caught_exceptions
                       ) == 0 and not py_db.has_plugin_exception_breaks:
                    py_db.disable_tracing_while_running_if_frame_eval()

            elif cmd_id == CMD_LOAD_SOURCE:
                path = text
                try:
                    if not IS_PY3K:  # In Python 3, the frame object will have unicode for the file, whereas on python 2 it has a byte-array encoded with the filesystem encoding.
                        path = path.encode(file_system_encoding)

                    path = pydevd_file_utils.norm_file_to_server(path)
                    f = open(path, 'r')
                    source = f.read()
                    cmd = py_db.cmd_factory.make_load_source_message(
                        seq, source)
                except:
                    cmd = py_db.cmd_factory.make_error_message(
                        seq, pydevd_tracing.get_exception_traceback_str())

            elif cmd_id == CMD_ADD_DJANGO_EXCEPTION_BREAK:
                exception = text
                plugin = py_db.get_plugin_lazy_init()
                if plugin is not None:
                    plugin.add_breakpoint('add_exception_breakpoint', py_db,
                                          'django', exception)
                    py_db.has_plugin_exception_breaks = py_db.plugin.has_exception_breaks(
                    )
                    py_db.enable_tracing_in_frames_while_running_if_frame_eval(
                    )

            elif cmd_id == CMD_REMOVE_DJANGO_EXCEPTION_BREAK:
                exception = text

                # I.e.: no need to initialize lazy (if we didn't have it in the first place, we can't remove
                # anything from it anyways).
                plugin = py_db.plugin
                if plugin is not None:
                    plugin.remove_exception_breakpoint(py_db, 'django',
                                                       exception)
                    py_db.has_plugin_exception_breaks = py_db.plugin.has_exception_breaks(
                    )
                if len(py_db.break_on_caught_exceptions
                       ) == 0 and not py_db.has_plugin_exception_breaks:
                    py_db.disable_tracing_while_running_if_frame_eval()

            elif cmd_id == CMD_EVALUATE_CONSOLE_EXPRESSION:
                # Command which takes care for the debug console communication
                if text != "":
                    thread_id, frame_id, console_command = text.split('\t', 2)
                    console_command, line = console_command.split('\t')

                    if console_command == 'EVALUATE':
                        int_cmd = InternalEvaluateConsoleExpression(
                            seq, thread_id, frame_id, line, buffer_output=True)

                    elif console_command == 'EVALUATE_UNBUFFERED':
                        int_cmd = InternalEvaluateConsoleExpression(
                            seq,
                            thread_id,
                            frame_id,
                            line,
                            buffer_output=False)

                    elif console_command == 'GET_COMPLETIONS':
                        int_cmd = InternalConsoleGetCompletions(
                            seq, thread_id, frame_id, line)

                    else:
                        raise ValueError('Unrecognized command: %s' %
                                         (console_command, ))

                    py_db.post_internal_command(int_cmd, thread_id)

            elif cmd_id == CMD_RUN_CUSTOM_OPERATION:
                # Command which runs a custom operation
                if text != "":
                    try:
                        location, custom = text.split('||', 1)
                    except:
                        sys.stderr.write(
                            'Custom operation now needs a || separator. Found: %s\n'
                            % (text, ))
                        raise

                    thread_id, frame_id, scopeattrs = location.split('\t', 2)

                    if scopeattrs.find(
                            '\t') != -1:  # there are attributes beyond scope
                        scope, attrs = scopeattrs.split('\t', 1)
                    else:
                        scope, attrs = (scopeattrs, None)

                    # : style: EXECFILE or EXEC
                    # : encoded_code_or_file: file to execute or code
                    # : fname: name of function to be executed in the resulting namespace
                    style, encoded_code_or_file, fnname = custom.split('\t', 3)
                    int_cmd = InternalRunCustomOperation(
                        seq, thread_id, frame_id, scope, attrs, style,
                        encoded_code_or_file, fnname)
                    py_db.post_internal_command(int_cmd, thread_id)

            elif cmd_id == CMD_IGNORE_THROWN_EXCEPTION_AT:
                if text:
                    replace = 'REPLACE:'  # Not all 3.x versions support u'REPLACE:', so, doing workaround.
                    if not IS_PY3K:
                        replace = unicode(replace)

                    if text.startswith(replace):
                        text = text[8:]
                        py_db.filename_to_lines_where_exceptions_are_ignored.clear(
                        )

                    if text:
                        for line in text.split(
                                '||'
                        ):  # Can be bulk-created (one in each line)
                            filename, line_number = line.split('|')
                            if not IS_PY3K:
                                filename = filename.encode(
                                    file_system_encoding)

                            filename = pydevd_file_utils.norm_file_to_server(
                                filename)

                            if os.path.exists(filename):
                                lines_ignored = py_db.filename_to_lines_where_exceptions_are_ignored.get(
                                    filename)
                                if lines_ignored is None:
                                    lines_ignored = py_db.filename_to_lines_where_exceptions_are_ignored[
                                        filename] = {}
                                lines_ignored[int(line_number)] = 1
                            else:
                                sys.stderr.write('pydev debugger: warning: trying to ignore exception thrown'\
                                    ' on file that does not exist: %s (will have no effect)\n' % (filename,))

            elif cmd_id == CMD_ENABLE_DONT_TRACE:
                if text:
                    true_str = 'true'  # Not all 3.x versions support u'str', so, doing workaround.
                    if not IS_PY3K:
                        true_str = unicode(true_str)

                    mode = text.strip() == true_str
                    pydevd_dont_trace.trace_filter(mode)

            elif cmd_id == CMD_REDIRECT_OUTPUT:
                if text:
                    py_db.enable_output_redirection('STDOUT' in text, 'STDERR'
                                                    in text)

            elif cmd_id == CMD_GET_NEXT_STATEMENT_TARGETS:
                thread_id, frame_id = text.split('\t', 1)

                int_cmd = InternalGetNextStatementTargets(
                    seq, thread_id, frame_id)
                py_db.post_internal_command(int_cmd, thread_id)

            elif cmd_id == CMD_SET_PROJECT_ROOTS:
                pydevd_utils.set_project_roots(text.split(u'\t'))

            elif cmd_id == CMD_THREAD_DUMP_TO_STDERR:
                pydevd_utils.dump_threads()

            elif cmd_id == CMD_STOP_ON_START:
                py_db.stop_on_start = text.strip() in ('True', 'true', '1')

            elif cmd_id == CMD_GET_EXCEPTION_DETAILS:
                thread_id = text
                t = pydevd_find_thread_by_id(thread_id)
                frame = None
                if t and not getattr(t, 'pydev_do_not_trace', None):
                    additional_info = set_additional_thread_info(t)
                    frame = additional_info.get_topmost_frame(t)
                try:
                    cmd = py_db.cmd_factory.make_get_exception_details_message(
                        seq, thread_id, frame)
                finally:
                    frame = None
                    t = None

            else:
                #I have no idea what this is all about
                cmd = py_db.cmd_factory.make_error_message(
                    seq, "unexpected command " + str(cmd_id))

            if cmd is not None:
                py_db.writer.add_command(cmd)
                del cmd

        except Exception:
            traceback.print_exc()
            try:
                from StringIO import StringIO
            except ImportError:
                from io import StringIO
            stream = StringIO()
            traceback.print_exc(file=stream)
            cmd = py_db.cmd_factory.make_error_message(
                seq,
                "Unexpected exception in process_net_command.\nInitial params: %s. Exception: %s"
                % (((cmd_id, seq, text), stream.getvalue())))

            py_db.writer.add_command(cmd)
    finally:
        py_db._main_lock.release()
예제 #20
0
def get_non_pydevd_threads():
    threads = threading.enumerate()
    return [t for t in threads if t and not getattr(t, 'is_pydev_daemon_thread', False)]