From de3ac19931c053eb11206a771b15f71973cf8419 Mon Sep 17 00:00:00 2001 From: Karthik Nadig Date: Tue, 27 Feb 2018 11:25:19 -0800 Subject: [PATCH 1/3] Make 'autogen' in 'IDMap.to_vscode' a required argument --- ptvsd/wrapper.py | 64 +++++++++++++++++++++++++++++++++--------------- 1 file changed, 44 insertions(+), 20 deletions(-) diff --git a/ptvsd/wrapper.py b/ptvsd/wrapper.py index 4ab8b2521..cd6ee20d9 100644 --- a/ptvsd/wrapper.py +++ b/ptvsd/wrapper.py @@ -115,7 +115,7 @@ def to_pydevd(self, vscode_id): # TODO: docstring return self._vscode_to_pydevd[vscode_id] - def to_vscode(self, pydevd_id, autogen=True): + def to_vscode(self, pydevd_id, autogen): # TODO: docstring try: return self._pydevd_to_vscode[pydevd_id] @@ -552,11 +552,16 @@ def on_threads(self, request, args): threads = [] for xthread in xthreads: - tid = self.thread_map.to_vscode(xthread['id']) + try: + tid = self.thread_map.to_vscode(xthread['id'], autogen=False) + except KeyError: + continue + try: name = unquote(xthread['name']) except KeyError: name = None + if not self.is_debugger_internal_thread(name): threads.append({'id': tid, 'name': name}) @@ -565,13 +570,18 @@ def on_threads(self, request, args): @async_handler def on_stackTrace(self, request, args): # TODO: docstring - tid = int(args['threadId']) + vsc_tid = int(args['threadId']) startFrame = int(args.get('startFrame', 0)) levels = int(args.get('levels', 0)) - tid = self.thread_map.to_pydevd(tid) + pyd_tid = self.thread_map.to_pydevd(vsc_tid) with self.stack_traces_lock: - xframes = self.stack_traces[tid] + try: + xframes = self.stack_traces[pyd_tid] + except KeyError: + # This means the stack was requested before the + # thread was suspended + xframes = [] totalFrames = len(xframes) if levels == 0: @@ -585,8 +595,8 @@ def on_stackTrace(self, request, args): if levels <= 0: break levels -= 1 - key = (tid, int(xframe['id'])) - fid = self.frame_map.to_vscode(key) + key = (pyd_tid, int(xframe['id'])) + fid = self.frame_map.to_vscode(key, autogen=True) name = unquote(xframe['name']) file = unquote(xframe['file']) line = int(xframe['line']) @@ -607,7 +617,7 @@ def on_scopes(self, request, args): vsc_fid = int(args['frameId']) pyd_tid, pyd_fid = self.frame_map.to_pydevd(vsc_fid) pyd_var = (pyd_tid, pyd_fid, 'FRAME') - vsc_var = self.var_map.to_vscode(pyd_var) + vsc_var = self.var_map.to_vscode(pyd_var, autogen=True) scope = { 'name': 'Locals', 'expensive': False, @@ -643,7 +653,7 @@ def on_variables(self, request, args): } if bool(xvar['isContainer']): pyd_child = pyd_var + (var['name'],) - var['variablesReference'] = self.var_map.to_vscode(pyd_child) + var['variablesReference'] = self.var_map.to_vscode(pyd_child, autogen=True) variables.append(var) self.send_response(request, variables=variables) @@ -657,7 +667,7 @@ def on_setVariable(self, request, args): # being set, and variable name; but pydevd wants the ID # (or rather path) of the variable itself. pyd_var += (args['name'],) - vsc_var = self.var_map.to_vscode(pyd_var) + vsc_var = self.var_map.to_vscode(pyd_var, autogen=True) cmd_args = [str(s) for s in pyd_var] + [args['value']] _, _, resp_args = yield self.pydevd_request( @@ -691,7 +701,7 @@ def on_evaluate(self, request, args): xvar = xml.var pyd_var = (pyd_tid, pyd_fid, 'EXPRESSION', expr) - vsc_var = self.var_map.to_vscode(pyd_var) + vsc_var = self.var_map.to_vscode(pyd_var, autogen=True) response = { 'type': unquote(xvar['type']), 'result': unquote(xvar['value']), @@ -810,12 +820,12 @@ def on_exceptionInfo(self, request, args): def on_pydevd_thread_create(self, seq, args): # TODO: docstring xml = untangle.parse(args).xml - tid = self.thread_map.to_vscode(xml.thread['id']) try: name = unquote(xml.thread['name']) except KeyError: name = None if not self.is_debugger_internal_thread(name): + tid = self.thread_map.to_vscode(xml.thread['id'], autogen=True) self.send_event('thread', reason='started', threadId=tid) @pydevd_events.handler(pydevd_comm.CMD_THREAD_KILL) @@ -832,7 +842,7 @@ def on_pydevd_thread_kill(self, seq, args): def on_pydevd_thread_suspend(self, seq, args): # TODO: docstring xml = untangle.parse(args).xml - tid = xml.thread['id'] + pyd_tid = xml.thread['id'] reason = int(xml.thread['stop_reason']) STEP_REASONS = { pydevd_comm.CMD_STEP_INTO, @@ -843,6 +853,12 @@ def on_pydevd_thread_suspend(self, seq, args): pydevd_comm.CMD_STEP_CAUGHT_EXCEPTION, pydevd_comm.CMD_ADD_EXCEPTION_BREAK } + + try: + vsc_tid = self.thread_map.to_vscode(pyd_tid, autogen=False) + except KeyError: + return + if reason in STEP_REASONS: reason = 'step' elif reason in EXCEPTION_REASONS: @@ -851,21 +867,24 @@ def on_pydevd_thread_suspend(self, seq, args): reason = 'breakpoint' else: reason = 'pause' + with self.stack_traces_lock: - self.stack_traces[tid] = xml.thread.frame - tid = self.thread_map.to_vscode(tid) - self.send_event('stopped', reason=reason, threadId=tid) + self.stack_traces[pyd_tid] = xml.thread.frame + + self.send_event('stopped', reason=reason, threadId=vsc_tid) @pydevd_events.handler(pydevd_comm.CMD_THREAD_RUN) def on_pydevd_thread_run(self, seq, args): # TODO: docstring pyd_tid, reason = args.split('\t') - vsc_tid = self.thread_map.to_vscode(pyd_tid) # Stack trace, and all frames and variables for this thread # are now invalid; clear their IDs. with self.stack_traces_lock: - del self.stack_traces[pyd_tid] + try: + del self.stack_traces[pyd_tid] + except KeyError: + pass for pyd_fid, vsc_fid in self.frame_map.pairs(): if pyd_fid[0] == pyd_tid: @@ -874,8 +893,13 @@ def on_pydevd_thread_run(self, seq, args): for pyd_var, vsc_var in self.var_map.pairs(): if pyd_var[0] == pyd_tid: self.var_map.remove(pyd_var, vsc_var) - - self.send_event('continued', threadId=vsc_tid) + + try: + vsc_tid = self.thread_map.to_vscode(pyd_tid, autogen=False) + except KeyError: + pass + else: + self.send_event('continued', threadId=vsc_tid) @pydevd_events.handler(pydevd_comm.CMD_SEND_CURR_EXCEPTION_TRACE) def on_pydevd_send_curr_exception_trace(self, seq, args): From a94d616b559e872e24f48da70400416b16112b29 Mon Sep 17 00:00:00 2001 From: Karthik Nadig Date: Tue, 27 Feb 2018 13:42:41 -0800 Subject: [PATCH 2/3] Fixes #138 by removing any whitespace characters in args before using --- ptvsd/wrapper.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/ptvsd/wrapper.py b/ptvsd/wrapper.py index cd6ee20d9..07e394e9e 100644 --- a/ptvsd/wrapper.py +++ b/ptvsd/wrapper.py @@ -832,11 +832,12 @@ def on_pydevd_thread_create(self, seq, args): def on_pydevd_thread_kill(self, seq, args): # TODO: docstring try: - tid = self.thread_map.to_vscode(args, autogen=False) + pyd_tid = args.strip() + vsc_tid = self.thread_map.to_vscode(pyd_tid, autogen=False) except KeyError: pass else: - self.send_event('thread', reason='exited', threadId=tid) + self.send_event('thread', reason='exited', threadId=vsc_tid) @pydevd_events.handler(pydevd_comm.CMD_THREAD_SUSPEND) def on_pydevd_thread_suspend(self, seq, args): @@ -877,6 +878,7 @@ def on_pydevd_thread_suspend(self, seq, args): def on_pydevd_thread_run(self, seq, args): # TODO: docstring pyd_tid, reason = args.split('\t') + pyd_tid = pyd_tid.strip() # Stack trace, and all frames and variables for this thread # are now invalid; clear their IDs. From 5825fbf7b5499ca3d0d44de2afadcf47f7deae24 Mon Sep 17 00:00:00 2001 From: Karthik Nadig Date: Tue, 27 Feb 2018 15:19:18 -0800 Subject: [PATCH 3/3] Send a create event for each new thread found while handling on_threads request --- ptvsd/wrapper.py | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/ptvsd/wrapper.py b/ptvsd/wrapper.py index 07e394e9e..1ce3d48bd 100644 --- a/ptvsd/wrapper.py +++ b/ptvsd/wrapper.py @@ -552,18 +552,21 @@ def on_threads(self, request, args): threads = [] for xthread in xthreads: - try: - tid = self.thread_map.to_vscode(xthread['id'], autogen=False) - except KeyError: - continue - try: name = unquote(xthread['name']) except KeyError: name = None - + if not self.is_debugger_internal_thread(name): - threads.append({'id': tid, 'name': name}) + pyd_tid = xthread['id'] + try: + vsc_tid = self.thread_map.to_vscode(pyd_tid, autogen=False) + except KeyError: + # This is a previously unseen thread + vsc_tid = self.thread_map.to_vscode(pyd_tid, autogen=True) + self.send_event('thread', reason='started', threadId=vsc_tid) + + threads.append({'id': vsc_tid, 'name': name}) self.send_response(request, threads=threads) @@ -825,6 +828,7 @@ def on_pydevd_thread_create(self, seq, args): except KeyError: name = None if not self.is_debugger_internal_thread(name): + # Any internal pydevd or ptvsd threads will be ignored everywhere tid = self.thread_map.to_vscode(xml.thread['id'], autogen=True) self.send_event('thread', reason='started', threadId=tid)