Skip to content

Commit 120e450

Browse files
authored
Merge pull request #1650 from zooba/issue-1648
Fixes #1648 Fix debug-attach and profiling for Python 3.6
2 parents 60a2bac + 881ec1e commit 120e450

File tree

8 files changed

+167
-32
lines changed

8 files changed

+167
-32
lines changed

Python/Product/Core/Core.csproj

+16
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,14 @@
7777
<Project>{89d51398-a003-44ba-b1b2-cfc6f8396d7e}</Project>
7878
<Name>Microsoft.PythonTools.BuildTasks</Name>
7979
</ProjectReference>
80+
<ProjectReference Include="..\DebuggerHelper\DebuggerHelper.vcxproj">
81+
<Project>{25956dfa-17a2-4109-b9e5-d46cce1ed52f}</Project>
82+
<Name>DebuggerHelper</Name>
83+
</ProjectReference>
84+
<ProjectReference Include="..\DebuggerHelper\DebuggerHelperX86.vcxproj">
85+
<Project>{a2a795f7-27d0-4801-88da-95b368f070ad}</Project>
86+
<Name>DebuggerHelperX86</Name>
87+
</ProjectReference>
8088
<ProjectReference Include="..\Debugger\Debugger.csproj">
8189
<Project>{DECC7971-FA58-4DB0-9561-BFFADD393BBD}</Project>
8290
<Name>Microsoft.PythonTools.Debugger</Name>
@@ -93,6 +101,14 @@
93101
<Project>{3814d9db-10e6-4478-bd98-6c5840612af8}</Project>
94102
<Name>Microsoft.PythonTools.ProjectWizards</Name>
95103
</ProjectReference>
104+
<ProjectReference Include="..\PyDebugAttach\PyDebugAttach.vcxproj">
105+
<Project>{ac19caa0-5c69-4b20-8a18-d4b6b65f22b8}</Project>
106+
<Name>PyDebugAttach</Name>
107+
</ProjectReference>
108+
<ProjectReference Include="..\PyDebugAttach\PyDebugAttachX86.vcxproj">
109+
<Project>{70e7eb43-81d3-4aa0-9870-0b304732aff2}</Project>
110+
<Name>PyDebugAttachX86</Name>
111+
</ProjectReference>
96112
<ProjectReference Include="..\PythonTools\PythonTools.csproj">
97113
<Project>{fa7be5f5-e04f-4613-b7ac-70ce10d1bb68}</Project>
98114
<Name>Microsoft.PythonTools</Name>

Python/Product/PyDebugAttach/PyDebugAttach.cpp

+11-14
Original file line numberDiff line numberDiff line change
@@ -722,8 +722,8 @@ long GetPythonThreadId(PythonVersion version, PyThreadState* curThread) {
722722
threadId = ((PyThreadState_25_27*)curThread)->thread_id;
723723
} else if (PyThreadState_30_33::IsFor(version)) {
724724
threadId = ((PyThreadState_30_33*)curThread)->thread_id;
725-
} else if (PyThreadState_34_35::IsFor(version)) {
726-
threadId = ((PyThreadState_34_35*)curThread)->thread_id;
725+
} else if (PyThreadState_34_36::IsFor(version)) {
726+
threadId = ((PyThreadState_34_36*)curThread)->thread_id;
727727
}
728728
return threadId;
729729
}
@@ -855,17 +855,14 @@ bool DoAttach(HMODULE module, ConnectionInfo& connInfo, bool isDebug) {
855855
auto getThreadTls = (PyThread_get_key_value*)GetProcAddress(module, "PyThread_get_key_value");
856856
auto setThreadTls = (PyThread_set_key_value*)GetProcAddress(module, "PyThread_set_key_value");
857857
auto delThreadTls = (PyThread_delete_key_value*)GetProcAddress(module, "PyThread_delete_key_value");
858-
auto pyGilStateEnsure = (PyGILState_EnsureFunc*)GetProcAddress(module, "PyGILState_Ensure");
859-
auto pyGilStateRelease = (PyGILState_ReleaseFunc*)GetProcAddress(module, "PyGILState_Release");
860858
auto PyCFrame_Type = (PyTypeObject*)GetProcAddress(module, "PyCFrame_Type");
861859

862860
if (addPendingCall == nullptr || curPythonThread == nullptr || interpHead == nullptr || gilEnsure == nullptr || gilRelease == nullptr || threadHead == nullptr ||
863861
initThreads == nullptr || releaseLock == nullptr || threadsInited == nullptr || threadNext == nullptr || threadSwap == nullptr ||
864862
pyDictNew == nullptr || pyCompileString == nullptr || pyEvalCode == nullptr || getDictItem == nullptr || call == nullptr ||
865863
getBuiltins == nullptr || dictSetItem == nullptr || intFromLong == nullptr || pyErrRestore == nullptr || pyErrFetch == nullptr ||
866864
errOccurred == nullptr || pyImportMod == nullptr || pyGetAttr == nullptr || pyNone == nullptr || pySetAttr == nullptr || boolFromLong == nullptr ||
867-
getThreadTls == nullptr || setThreadTls == nullptr || delThreadTls == nullptr ||
868-
pyGilStateEnsure == nullptr || pyGilStateRelease == nullptr) {
865+
getThreadTls == nullptr || setThreadTls == nullptr || delThreadTls == nullptr) {
869866
// we're missing some APIs, we cannot attach.
870867
connInfo.ReportError(ConnError_PythonNotFound);
871868
return false;
@@ -975,13 +972,13 @@ bool DoAttach(HMODULE module, ConnectionInfo& connInfo, bool isDebug) {
975972
// Py_InitThreads to bring up multi-threading.
976973
// Some context here: http://bugs.python.org/issue11329
977974
// http://pytools.codeplex.com/workitem/834
978-
gilState = pyGilStateEnsure();
975+
gilState = gilEnsure();
979976
}
980977
initThreads();
981978

982979
if (version >= PythonVersion_32) {
983980
// we will release the GIL here
984-
pyGilStateRelease(gilState);
981+
gilRelease(gilState);
985982
} else {
986983
releaseLock();
987984
}
@@ -1149,8 +1146,8 @@ bool DoAttach(HMODULE module, ConnectionInfo& connInfo, bool isDebug) {
11491146
frame = ((PyThreadState_25_27*)curThread)->frame;
11501147
} else if (PyThreadState_30_33::IsFor(version)) {
11511148
frame = ((PyThreadState_30_33*)curThread)->frame;
1152-
} else if (PyThreadState_34_35::IsFor(version)) {
1153-
frame = ((PyThreadState_34_35*)curThread)->frame;
1149+
} else if (PyThreadState_34_36::IsFor(version)) {
1150+
frame = ((PyThreadState_34_36*)curThread)->frame;
11541151
}
11551152

11561153
auto threadObj = PyObjectHolder(isDebug, call(new_thread.ToPython(), pyThreadId.ToPython(), pyTrue, frame, NULL));
@@ -1342,8 +1339,8 @@ int TraceGeneral(int interpreterId, PyObject *obj, PyFrameObject *frame, int wha
13421339
((PyThreadState_25_27*)curThread)->c_tracefunc(((PyThreadState_25_27*)curThread)->c_traceobj, frame, what, arg);
13431340
} else if (PyThreadState_30_33::IsFor(version)) {
13441341
((PyThreadState_30_33*)curThread)->c_tracefunc(((PyThreadState_30_33*)curThread)->c_traceobj, frame, what, arg);
1345-
} else if (PyThreadState_34_35::IsFor(version)) {
1346-
((PyThreadState_34_35*)curThread)->c_tracefunc(((PyThreadState_34_35*)curThread)->c_traceobj, frame, what, arg);
1342+
} else if (PyThreadState_34_36::IsFor(version)) {
1343+
((PyThreadState_34_36*)curThread)->c_tracefunc(((PyThreadState_34_36*)curThread)->c_traceobj, frame, what, arg);
13471344
}
13481345
}
13491346
return 0;
@@ -1387,8 +1384,8 @@ void SetInitialTraceFunc(DWORD interpreterId, PyThreadState *thread) {
13871384
gilstate_counter = ((PyThreadState_25_27*)thread)->gilstate_counter;
13881385
} else if (PyThreadState_30_33::IsFor(version)) {
13891386
gilstate_counter = ((PyThreadState_30_33*)thread)->gilstate_counter;
1390-
} else if (PyThreadState_34_35::IsFor(version)) {
1391-
gilstate_counter = ((PyThreadState_34_35*)thread)->gilstate_counter;
1387+
} else if (PyThreadState_34_36::IsFor(version)) {
1388+
gilstate_counter = ((PyThreadState_34_36*)thread)->gilstate_counter;
13921389
}
13931390

13941391
if (gilstate_counter == 1) {

Python/Product/VsPyProf/PythonApi.cpp

+13-3
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ VsPyProf* VsPyProf::Create(HMODULE pythonModule) {
8888
}
8989

9090
if ((major == 2 && (minor >= 4 && minor <= 7)) ||
91-
(major == 3 && (minor >= 0 && minor <= 5))) {
91+
(major == 3 && (minor >= 0 && minor <= 6))) {
9292
return new VsPyProf(pythonModule,
9393
major,
9494
minor,
@@ -134,6 +134,8 @@ bool VsPyProf::GetUserToken(PyFrameObject* frameObj, DWORD_PTR& func, DWORD_PTR&
134134
filename = ((PyCodeObject30_32*)codeObj)->co_filename;
135135
} else if (PyCodeObject33_35::IsFor(MajorVersion, MinorVersion)) {
136136
filename = ((PyCodeObject33_35*)codeObj)->co_filename;
137+
} else if (PyCodeObject36::IsFor(MajorVersion, MinorVersion)) {
138+
filename = ((PyCodeObject36*)codeObj)->co_filename;
137139
}
138140
module = (DWORD_PTR)filename;
139141

@@ -210,6 +212,9 @@ bool VsPyProf::GetUserToken(PyFrameObject* frameObj, DWORD_PTR& func, DWORD_PTR&
210212
} else if (PyCodeObject33_35::IsFor(MajorVersion, MinorVersion)) {
211213
RegisterName(func, ((PyCodeObject33_35*)codeObj)->co_name, &moduleName);
212214
lineno = ((PyCodeObject33_35*)codeObj)->co_firstlineno;
215+
} else if (PyCodeObject36::IsFor(MajorVersion, MinorVersion)) {
216+
RegisterName(func, ((PyCodeObject36*)codeObj)->co_name, &moduleName);
217+
lineno = ((PyCodeObject36*)codeObj)->co_firstlineno;
213218
}
214219

215220
// give the profiler the line number of this function
@@ -242,6 +247,9 @@ wstring VsPyProf::GetClassNameFromFrame(PyFrameObject* frameObj, PyObject *codeO
242247
} else if (PyCodeObject33_35::IsFor(MajorVersion, MinorVersion)) {
243248
argCount = ((PyCodeObject33_35*)codeObj)->co_argcount;
244249
argNames = (PyTupleObject*)((PyCodeObject33_35*)codeObj)->co_varnames;
250+
} else if (PyCodeObject36::IsFor(MajorVersion, MinorVersion)) {
251+
argCount = ((PyCodeObject36*)codeObj)->co_argcount;
252+
argNames = (PyTupleObject*)((PyCodeObject36*)codeObj)->co_varnames;
245253
}
246254

247255
if (argCount != 0 && argNames->ob_type == PyTuple_Type) {
@@ -252,8 +260,8 @@ wstring VsPyProf::GetClassNameFromFrame(PyFrameObject* frameObj, PyObject *codeO
252260
PyObject* self = nullptr;
253261
if (PyFrameObject25_33::IsFor(MajorVersion, MinorVersion)) {
254262
self = ((PyFrameObject25_33*)frameObj)->f_localsplus[0];
255-
} else if (PyFrameObject34_35::IsFor(MajorVersion, MinorVersion)) {
256-
self = ((PyFrameObject34_35*)frameObj)->f_localsplus[0];
263+
} else if (PyFrameObject34_36::IsFor(MajorVersion, MinorVersion)) {
264+
self = ((PyFrameObject34_36*)frameObj)->f_localsplus[0];
257265
}
258266
return GetClassNameFromSelf(self, codeObj);
259267
}
@@ -281,6 +289,8 @@ wstring VsPyProf::GetClassNameFromSelf(PyObject* self, PyObject *codeObj) {
281289
nameObj = ((PyCodeObject30_32*)codeObj)->co_name;
282290
} else if (PyCodeObject33_35::IsFor(MajorVersion, MinorVersion)) {
283291
nameObj = ((PyCodeObject33_35*)codeObj)->co_name;
292+
} else if (PyCodeObject36::IsFor(MajorVersion, MinorVersion)) {
293+
nameObj = ((PyCodeObject36*)codeObj)->co_name;
284294
}
285295
GetNameAscii(nameObj, codeName);
286296

Python/Product/VsPyProf/python.h

+45-12
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,8 @@ enum PythonVersion {
2828
PythonVersion_32 = 0x0302,
2929
PythonVersion_33 = 0x0303,
3030
PythonVersion_34 = 0x0304,
31-
PythonVersion_35 = 0x0305
31+
PythonVersion_35 = 0x0305,
32+
PythonVersion_36 = 0x0306
3233
};
3334

3435

@@ -144,7 +145,38 @@ class PyCodeObject33_35 : public PyObject {
144145
}
145146
};
146147

147-
// 2.5 - 3.1
148+
// 3.6
149+
class PyCodeObject36 : public PyObject {
150+
public:
151+
int co_argcount; /* #arguments, except *args */
152+
int co_kwonlyargcount; /* #keyword only arguments */
153+
int co_nlocals; /* #local variables */
154+
int co_stacksize; /* #entries needed for evaluation stack */
155+
int co_flags; /* CO_..., see below */
156+
int co_firstlineno; /* first source line number */
157+
PyObject *co_code; /* instruction opcodes */
158+
PyObject *co_consts; /* list (constants used) */
159+
PyObject *co_names; /* list of strings (names used) */
160+
PyObject *co_varnames; /* tuple of strings (local variable names) */
161+
PyObject *co_freevars; /* tuple of strings (free variable names) */
162+
PyObject *co_cellvars; /* tuple of strings (cell variable names) */
163+
/* The rest doesn't count for hash or comparisons */
164+
unsigned char *co_cell2arg; /* Maps cell vars which are arguments. */
165+
PyObject *co_filename; /* unicode (where it was loaded from) */
166+
PyObject *co_name; /* unicode (name, for reference) */
167+
PyObject *co_lnotab; /* string (encoding addr<->lineno mapping) */
168+
void *co_zombieframe; /* for optimization only (see frameobject.c) */
169+
170+
static bool IsFor(int majorVersion, int minorVersion) {
171+
return majorVersion == 3 && minorVersion >= 6;
172+
}
173+
174+
static bool IsFor(PythonVersion version) {
175+
return version >= PythonVersion_36;
176+
}
177+
};
178+
179+
// 2.5 - 3.6
148180
class PyFunctionObject : public PyObject {
149181
public:
150182
PyObject *func_code; /* A code object */
@@ -175,7 +207,7 @@ typedef struct {
175207
long hash; /* Hash value; -1 if not set */
176208
} PyUnicodeObject;
177209

178-
// 2.4 - 3.5 compatible
210+
// 2.4 - 3.6 compatible
179211
class PyFrameObject : public PyVarObject {
180212
public:
181213
PyFrameObject *f_back; /* previous frame, or NULL */
@@ -216,7 +248,7 @@ class PyFrameObject25_33 : public PyFrameObject {
216248
}
217249
};
218250

219-
class PyFrameObject34_35 : public PyFrameObject {
251+
class PyFrameObject34_36 : public PyFrameObject {
220252
public:
221253
/* Borrowed reference to a generator, or NULL */
222254
PyObject *f_gen;
@@ -231,14 +263,14 @@ class PyFrameObject34_35 : public PyFrameObject {
231263
PyObject *f_localsplus[1]; /* locals+stack, dynamically sized */
232264

233265
static bool IsFor(int majorVersion, int minorVersion) {
234-
return majorVersion == 3 && minorVersion >= 4 && minorVersion <= 5;
266+
return majorVersion == 3 && minorVersion >= 4 && minorVersion <= 6;
235267
}
236268
};
237269

238270

239271
typedef void (*destructor)(PyObject *);
240272

241-
// 2.4 - 3.5
273+
// 2.4 - 3.6
242274
class PyMethodDef {
243275
public:
244276
char *ml_name; /* The name of the built-in function/method */
@@ -261,7 +293,7 @@ class PyTypeObject : public PyVarObject {
261293
void* tp_setattr;
262294
union {
263295
void* tp_compare; /* 2.4 - 3.4 */
264-
void* tp_as_async; /* 3.5 */
296+
void* tp_as_async; /* 3.5 - 3.6 */
265297
};
266298
void* tp_repr;
267299

@@ -331,7 +363,7 @@ class PyTypeObject : public PyVarObject {
331363
unsigned int tp_version_tag;
332364
};
333365

334-
// 2.4 - 3.5
366+
// 2.4 - 3.6
335367
class PyTupleObject : public PyVarObject {
336368
public:
337369
PyObject *ob_item[1];
@@ -342,7 +374,7 @@ class PyTupleObject : public PyVarObject {
342374
*/
343375
};
344376

345-
// 2.4 - 3.5
377+
// 2.4 - 3.6
346378
class PyCFunctionObject : public PyObject {
347379
public:
348380
PyMethodDef *m_ml; /* Description of the C function to call */
@@ -473,7 +505,7 @@ class PyThreadState_30_33 : public PyThreadState {
473505
}
474506
};
475507

476-
class PyThreadState_34_35 : public PyThreadState {
508+
class PyThreadState_34_36 : public PyThreadState {
477509
public:
478510
PyThreadState *prev;
479511
PyThreadState *next;
@@ -513,11 +545,11 @@ class PyThreadState_34_35 : public PyThreadState {
513545

514546
/* XXX signal handlers should also be here */
515547
static bool IsFor(int majorVersion, int minorVersion) {
516-
return majorVersion == 3 && minorVersion >= 4 && minorVersion <= 5;
548+
return majorVersion == 3 && minorVersion >= 4 && minorVersion <= 6;
517549
}
518550

519551
static bool IsFor(PythonVersion version) {
520-
return version >= PythonVersion_34 && version <= PythonVersion_35;
552+
return version >= PythonVersion_34 && version <= PythonVersion_36;
521553
}
522554
};
523555

@@ -570,6 +602,7 @@ static PythonVersion GetPythonVersion(HMODULE hMod) {
570602
case '3': return PythonVersion_33;
571603
case '4': return PythonVersion_34;
572604
case '5': return PythonVersion_35;
605+
case '6': return PythonVersion_36;
573606
}
574607
}
575608
}

Python/Tests/Core/DebugReplEvaluatorTests.cs

+16-1
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ public void ErrorInInput() {
116116
Assert.AreEqual(@"Traceback (most recent call last):
117117
File ""<debug input>"", line 1, in <module>
118118
NameError: name 'does_not_exist' is not defined
119-
", _window.Error);
119+
".Replace("\r\n", "\n"), _window.Error.Replace("\r\n", "\n"));
120120
}
121121

122122
[TestMethod, Priority(3)]
@@ -434,6 +434,21 @@ internal override PythonVersion Version {
434434
}
435435
}
436436

437+
[TestClass]
438+
public class DebugReplEvaluatorTests36 : DebugReplEvaluatorTests {
439+
[ClassInitialize]
440+
public static new void DoDeployment(TestContext context) {
441+
AssertListener.Initialize();
442+
PythonTestData.Deploy();
443+
}
444+
445+
internal override PythonVersion Version {
446+
get {
447+
return PythonPaths.Python36 ?? PythonPaths.Python36_x64;
448+
}
449+
}
450+
}
451+
437452
[TestClass]
438453
public class DebugReplEvaluatorTests27 : DebugReplEvaluatorTests {
439454
[ClassInitialize]

Python/Tests/DebuggerTests/AttachTests.cs

+29-2
Original file line numberDiff line numberDiff line change
@@ -807,7 +807,10 @@ public void AttachPtvsd() {
807807
string script = TestData.GetPath(@"TestData\DebuggerProject\AttachPtvsd.py");
808808
var psi = new ProcessStartInfo(Version.InterpreterPath, PtvsdInterpreterArguments + " \"" + script + "\"") {
809809
WorkingDirectory = TestData.GetPath(),
810-
UseShellExecute = false
810+
UseShellExecute = false,
811+
RedirectStandardOutput = true,
812+
RedirectStandardError = true,
813+
CreateNoWindow = true
811814
};
812815

813816
var p = Process.Start(psi);
@@ -822,7 +825,7 @@ public void AttachPtvsd() {
822825
break;
823826
} catch (SocketException) {
824827
// Failed to connect - the process might have not started yet, so keep trying a few more times.
825-
if (i >= 5) {
828+
if (i >= 5 || p.HasExited) {
826829
throw;
827830
}
828831
}
@@ -862,6 +865,8 @@ public void AttachPtvsd() {
862865
DetachProcess(proc);
863866
}
864867
} finally {
868+
Console.WriteLine(p.StandardOutput.ReadToEnd());
869+
Console.WriteLine(p.StandardError.ReadToEnd());
865870
DisposeProcess(p);
866871
}
867872
}
@@ -1046,6 +1051,28 @@ internal override PythonVersion Version {
10461051
}
10471052
}
10481053

1054+
[TestClass]
1055+
public class AttachTests36 : AttachTests {
1056+
internal override PythonVersion Version {
1057+
get {
1058+
return PythonPaths.Python36;
1059+
}
1060+
}
1061+
1062+
public override void AttachNewThread_PyThreadState_New() {
1063+
// PyEval_AcquireLock deprecated in 3.2
1064+
}
1065+
}
1066+
1067+
[TestClass]
1068+
public class AttachTests36_x64 : AttachTests35 {
1069+
internal override PythonVersion Version {
1070+
get {
1071+
return PythonPaths.Python36_x64;
1072+
}
1073+
}
1074+
}
1075+
10491076
[TestClass]
10501077
public class AttachTests25 : AttachTests {
10511078
internal override PythonVersion Version {

0 commit comments

Comments
 (0)