mirror of
https://github.com/microsoft/debugpy.git
synced 2025-12-23 08:48:12 +00:00
Get debug attach to work for 3.12 (#1683)
* Get debug attach to work for 3.12 * Skip flakey test and update binaries * Fix the skip if to work correctly
This commit is contained in:
parent
ae6812bdac
commit
25955a05d8
21 changed files with 30 additions and 13 deletions
|
|
@ -308,7 +308,7 @@ def run_python_code_windows(pid, python_code, connect_debugger_tracing=False, sh
|
|||
args = [target_executable, str(pid), target_dll_run_on_dllmain]
|
||||
subprocess.check_call(args)
|
||||
|
||||
if not event.wait_for_event_set(15):
|
||||
if not event.wait_for_event_set(30):
|
||||
print("Timeout error: the attach may not have completed.")
|
||||
sys.stdout.flush()
|
||||
print("--- Finished dll injection ---\n")
|
||||
|
|
|
|||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -11,6 +11,7 @@ typedef PyThreadState* (PyInterpreterState_ThreadHead)(PyInterpreterState* inter
|
|||
typedef PyThreadState* (PyThreadState_Next)(PyThreadState *tstate);
|
||||
typedef PyThreadState* (PyThreadState_Swap)(PyThreadState *tstate);
|
||||
typedef PyThreadState* (_PyThreadState_UncheckedGet)();
|
||||
typedef PyThreadState* (_PyThreadState_GetCurrent)();
|
||||
typedef PyObject* (PyObject_CallFunctionObjArgs)(PyObject *callable, ...); // call w/ varargs, last arg should be nullptr
|
||||
typedef PyObject* (PyInt_FromLong)(long);
|
||||
typedef PyObject* (PyErr_Occurred)();
|
||||
|
|
|
|||
|
|
@ -21,7 +21,9 @@ enum PythonVersion {
|
|||
PythonVersion_38 = 0x0308,
|
||||
PythonVersion_39 = 0x0309,
|
||||
PythonVersion_310 = 0x030A,
|
||||
PythonVersion_311 = 0x030B
|
||||
PythonVersion_311 = 0x030B,
|
||||
PythonVersion_312 = 0x030C,
|
||||
PythonVersion_313 = 0x030D,
|
||||
};
|
||||
|
||||
|
||||
|
|
@ -70,6 +72,12 @@ static PythonVersion GetPythonVersion(void *module) {
|
|||
if(version[3] == '1'){
|
||||
return PythonVersion_311;
|
||||
}
|
||||
if(version[3] == '2'){
|
||||
return PythonVersion_312;
|
||||
}
|
||||
if(version[3] == '3'){
|
||||
return PythonVersion_313;
|
||||
}
|
||||
}
|
||||
return PythonVersion_Unknown; // we don't care about 3.1 anymore...
|
||||
|
||||
|
|
|
|||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -41,7 +41,6 @@
|
|||
|
||||
// Access to std::cout and std::endl
|
||||
#include <iostream>
|
||||
#include <mutex>
|
||||
// DECLDIR will perform an export for us
|
||||
#define DLL_EXPORT
|
||||
|
||||
|
|
@ -108,9 +107,9 @@ struct InitializeThreadingInfo {
|
|||
PyImport_ImportModule* pyImportMod;
|
||||
PyEval_Lock* initThreads;
|
||||
|
||||
std::mutex mutex;
|
||||
HANDLE initedEvent; // Note: only access with mutex locked (and check if not already nullptr).
|
||||
bool completed; // Note: only access with mutex locked
|
||||
CRITICAL_SECTION cs;
|
||||
HANDLE initedEvent; // Note: only access with cs locked (and check if not already nullptr).
|
||||
bool completed; // Note: only access with cs locked
|
||||
};
|
||||
|
||||
|
||||
|
|
@ -122,12 +121,12 @@ int AttachCallback(void *voidInitializeThreadingInfo) {
|
|||
initializeThreadingInfo->initThreads(); // Note: calling multiple times is ok.
|
||||
initializeThreadingInfo->pyImportMod("threading");
|
||||
|
||||
initializeThreadingInfo->mutex.lock();
|
||||
EnterCriticalSection(&initializeThreadingInfo->cs);
|
||||
initializeThreadingInfo->completed = true;
|
||||
if(initializeThreadingInfo->initedEvent != nullptr) {
|
||||
SetEvent(initializeThreadingInfo->initedEvent);
|
||||
}
|
||||
initializeThreadingInfo->completed = true;
|
||||
initializeThreadingInfo->mutex.unlock();
|
||||
LeaveCriticalSection(&initializeThreadingInfo->cs);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -311,6 +310,11 @@ extern "C"
|
|||
// Either _PyThreadState_Current or _PyThreadState_UncheckedGet are required
|
||||
DEFINE_PROC_NO_CHECK(curPythonThread, PyThreadState**, "_PyThreadState_Current", -220); // optional
|
||||
DEFINE_PROC_NO_CHECK(getPythonThread, _PyThreadState_UncheckedGet*, "_PyThreadState_UncheckedGet", -230); // optional
|
||||
DEFINE_PROC_NO_CHECK(getPythonThread13, _PyThreadState_GetCurrent*, "_PyThreadState_GetCurrent", -231); // optional
|
||||
if (getPythonThread == nullptr && getPythonThread13 != nullptr) {
|
||||
std::cout << "Using Python 3.13 or later, using _PyThreadState_GetCurrent" << std::endl << std::flush;
|
||||
getPythonThread = getPythonThread13;
|
||||
}
|
||||
|
||||
if (curPythonThread == nullptr && getPythonThread == nullptr) {
|
||||
// we're missing some APIs, we cannot attach.
|
||||
|
|
@ -318,6 +322,7 @@ extern "C"
|
|||
return -240;
|
||||
}
|
||||
|
||||
|
||||
// Either _Py_CheckInterval or _PyEval_[GS]etSwitchInterval are useful, but not required
|
||||
DEFINE_PROC_NO_CHECK(intervalCheck, int*, "_Py_CheckInterval", -250); // optional
|
||||
DEFINE_PROC_NO_CHECK(getSwitchInterval, _PyEval_GetSwitchInterval*, "_PyEval_GetSwitchInterval", -260); // optional
|
||||
|
|
@ -368,6 +373,8 @@ extern "C"
|
|||
initializeThreadingInfo->pyImportMod = pyImportMod;
|
||||
initializeThreadingInfo->initThreads = initThreads;
|
||||
initializeThreadingInfo->initedEvent = CreateEvent(nullptr, TRUE, FALSE, nullptr);
|
||||
InitializeCriticalSection(&initializeThreadingInfo->cs);
|
||||
|
||||
|
||||
// Add the call to initialize threading.
|
||||
addPendingCall(&AttachCallback, initializeThreadingInfo);
|
||||
|
|
@ -375,15 +382,16 @@ extern "C"
|
|||
::WaitForSingleObject(initializeThreadingInfo->initedEvent, 5000);
|
||||
|
||||
// Whether this completed or not, release the event handle as we won't use it anymore.
|
||||
initializeThreadingInfo->mutex.lock();
|
||||
EnterCriticalSection(&initializeThreadingInfo->cs);
|
||||
CloseHandle(initializeThreadingInfo->initedEvent);
|
||||
bool completed = initializeThreadingInfo->completed;
|
||||
initializeThreadingInfo->initedEvent = nullptr;
|
||||
initializeThreadingInfo->mutex.unlock();
|
||||
LeaveCriticalSection(&initializeThreadingInfo->cs);
|
||||
|
||||
if(completed) {
|
||||
// Note that this structure will leak if addPendingCall did not complete in the timeout
|
||||
// (we can't release now because it's possible that it'll still be called).
|
||||
DeleteCriticalSection(&initializeThreadingInfo->cs);
|
||||
delete initializeThreadingInfo;
|
||||
if (showDebugInfo) {
|
||||
std::cout << "addPendingCall to initialize threads/import threading completed. " << std::endl << std::flush;
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ setlocal
|
|||
|
||||
@set VSWHERE=%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe
|
||||
@echo Using vswhere at %VSWHERE%
|
||||
@for /f "usebackq tokens=*" %%i in (`"%VSWHERE%" -latest -products * -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -property installationPath`) do set VSDIR=%%i
|
||||
@for /f "usebackq tokens=*" %%i in (`"%VSWHERE%" -prerelease -latest -products * -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -property installationPath`) do set VSDIR=%%i
|
||||
@echo Using Visual C++ at %VSDIR%
|
||||
|
||||
call "%VSDIR%\VC\Auxiliary\Build\vcvarsall.bat" x86 -vcvars_spectre_libs=spectre
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ from tests.patterns import some
|
|||
|
||||
@pytest.mark.parametrize("stop_method", ["breakpoint", "pause"])
|
||||
@pytest.mark.parametrize("is_client_connected", ["is_client_connected", ""])
|
||||
@pytest.mark.parametrize("wait_for_client", ["wait_for_client", ""])
|
||||
@pytest.mark.parametrize("wait_for_client", ["wait_for_client", pytest.param("", marks=pytest.mark.skipif(sys.platform.startswith("darwin"), reason="Flakey test on Mac"))])
|
||||
def test_attach_api(pyfile, wait_for_client, is_client_connected, stop_method):
|
||||
@pyfile
|
||||
def code_to_debug():
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue