diff options
author | László Kiss Kollár <kiss.kollar.laszlo@gmail.com> | 2025-07-10 18:44:24 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2025-07-10 18:44:24 +0100 |
commit | 59acdba820f75081cfb47ad6e71044d022854cbc (patch) | |
tree | 870d1dde8659c961ac4ca447d8fa22c312402b07 /Python/remote_debug.h | |
parent | 35e2c359703e076256c1249b74b87043972e04d6 (diff) | |
download | cpython-59acdba820f75081cfb47ad6e71044d022854cbc.tar.gz cpython-59acdba820f75081cfb47ad6e71044d022854cbc.zip |
gh-135953: Implement sampling tool under profile.sample (#135998)
Implement a statistical sampling profiler that can profile external
Python processes by PID. Uses the _remote_debugging module and converts
the results to pstats-compatible format for analysis.
Co-authored-by: Pablo Galindo <pablogsal@gmail.com>
Diffstat (limited to 'Python/remote_debug.h')
-rw-r--r-- | Python/remote_debug.h | 22 |
1 files changed, 21 insertions, 1 deletions
diff --git a/Python/remote_debug.h b/Python/remote_debug.h index 8f9b6cd4c49..5324a7aaa6f 100644 --- a/Python/remote_debug.h +++ b/Python/remote_debug.h @@ -751,6 +751,14 @@ search_linux_map_for_section(proc_handle_t *handle, const char* secname, const c #ifdef MS_WINDOWS +static int is_process_alive(HANDLE hProcess) { + DWORD exitCode; + if (GetExitCodeProcess(hProcess, &exitCode)) { + return exitCode == STILL_ACTIVE; + } + return 0; +} + static void* analyze_pe(const wchar_t* mod_path, BYTE* remote_base, const char* secname) { HANDLE hFile = CreateFileW(mod_path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (hFile == INVALID_HANDLE_VALUE) { @@ -911,7 +919,9 @@ _Py_RemoteDebug_GetPyRuntimeAddress(proc_handle_t* handle) _PyErr_ChainExceptions1(exc); } #else - Py_UNREACHABLE(); + _set_debug_exception_cause(PyExc_RuntimeError, + "Reading the PyRuntime section is not supported on this platform"); + return 0; #endif return address; @@ -981,6 +991,13 @@ _Py_RemoteDebug_ReadRemoteMemory(proc_handle_t *handle, uintptr_t remote_address SIZE_T result = 0; do { if (!ReadProcessMemory(handle->hProcess, (LPCVOID)(remote_address + result), (char*)dst + result, len - result, &read_bytes)) { + // Check if the process is still alive: we need to be able to tell our caller + // that the process is dead and not just that the read failed. + if (!is_process_alive(handle->hProcess)) { + _set_errno(ESRCH); + PyErr_SetFromErrno(PyExc_OSError); + return -1; + } PyErr_SetFromWindowsErr(0); DWORD error = GetLastError(); _set_debug_exception_cause(PyExc_OSError, @@ -1013,6 +1030,9 @@ _Py_RemoteDebug_ReadRemoteMemory(proc_handle_t *handle, uintptr_t remote_address return read_remote_memory_fallback(handle, remote_address, len, dst); } PyErr_SetFromErrno(PyExc_OSError); + if (errno == ESRCH) { + return -1; + } _set_debug_exception_cause(PyExc_OSError, "process_vm_readv failed for PID %d at address 0x%lx " "(size %zu, partial read %zd bytes): %s", |