Skip to content

Commit 9a5db8f

Browse files
committed
gh-139275: Fix compilation of Modules/_remote_debugging_module.c when the system doesn't have process_vm_readv
1 parent 76b2297 commit 9a5db8f

File tree

2 files changed

+133
-2
lines changed

2 files changed

+133
-2
lines changed

Modules/_remote_debugging_module.c

Lines changed: 132 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -824,7 +824,7 @@ _Py_RemoteDebug_GetAsyncioDebugAddress(proc_handle_t* handle)
824824
PyErr_SetString(PyExc_RuntimeError, "Failed to find the AsyncioDebug section in the process.");
825825
_PyErr_ChainExceptions1(exc);
826826
}
827-
#elif defined(__linux__)
827+
#elif defined(__linux__) && HAVE_PROCESS_VM_READV
828828
// On Linux, search for asyncio debug in executable or DLL
829829
address = search_linux_map_for_section(handle, "AsyncioDebug", "python");
830830
if (address == 0) {
@@ -2453,6 +2453,137 @@ process_frame_chain(
24532453
return 0;
24542454
}
24552455

2456+
<<<<<<< Updated upstream
2457+
=======
2458+
static int
2459+
get_thread_status(RemoteUnwinderObject *unwinder, uint64_t tid, uint64_t pthread_id) {
2460+
#if defined(__APPLE__) && TARGET_OS_OSX
2461+
if (unwinder->thread_id_offset == 0) {
2462+
uint64_t *tids = (uint64_t *)PyMem_Malloc(MAX_NATIVE_THREADS * sizeof(uint64_t));
2463+
if (!tids) {
2464+
PyErr_NoMemory();
2465+
return -1;
2466+
}
2467+
int n = proc_pidinfo(unwinder->handle.pid, PROC_PIDLISTTHREADS, 0, tids, MAX_NATIVE_THREADS * sizeof(uint64_t)) / sizeof(uint64_t);
2468+
if (n <= 0) {
2469+
PyMem_Free(tids);
2470+
return THREAD_STATE_UNKNOWN;
2471+
}
2472+
uint64_t min_offset = UINT64_MAX;
2473+
for (int i = 0; i < n; i++) {
2474+
uint64_t offset = tids[i] - pthread_id;
2475+
if (offset < min_offset) {
2476+
min_offset = offset;
2477+
}
2478+
}
2479+
unwinder->thread_id_offset = min_offset;
2480+
PyMem_Free(tids);
2481+
}
2482+
struct proc_threadinfo ti;
2483+
uint64_t tid_with_offset = pthread_id + unwinder->thread_id_offset;
2484+
if (proc_pidinfo(unwinder->handle.pid, PROC_PIDTHREADINFO, tid_with_offset, &ti, sizeof(ti)) != sizeof(ti)) {
2485+
return THREAD_STATE_UNKNOWN;
2486+
}
2487+
if (ti.pth_run_state == TH_STATE_RUNNING) {
2488+
return THREAD_STATE_RUNNING;
2489+
}
2490+
return THREAD_STATE_IDLE;
2491+
#elif defined(__linux__) && HAVE_PROCESS_VM_READV
2492+
char stat_path[256];
2493+
char buffer[2048] = "";
2494+
2495+
snprintf(stat_path, sizeof(stat_path), "/proc/%d/task/%lu/stat", unwinder->handle.pid, tid);
2496+
2497+
int fd = open(stat_path, O_RDONLY);
2498+
if (fd == -1) {
2499+
return THREAD_STATE_UNKNOWN;
2500+
}
2501+
2502+
if (read(fd, buffer, 2047) == 0) {
2503+
close(fd);
2504+
return THREAD_STATE_UNKNOWN;
2505+
}
2506+
close(fd);
2507+
2508+
char *p = strchr(buffer, ')');
2509+
if (!p) {
2510+
return THREAD_STATE_UNKNOWN;
2511+
}
2512+
2513+
p += 2; // Skip ") "
2514+
if (*p == ' ') {
2515+
p++;
2516+
}
2517+
2518+
switch (*p) {
2519+
case 'R': // Running
2520+
return THREAD_STATE_RUNNING;
2521+
case 'S': // Interruptible sleep
2522+
case 'D': // Uninterruptible sleep
2523+
case 'T': // Stopped
2524+
case 'Z': // Zombie
2525+
case 'I': // Idle kernel thread
2526+
return THREAD_STATE_IDLE;
2527+
default:
2528+
return THREAD_STATE_UNKNOWN;
2529+
}
2530+
#elif defined(MS_WINDOWS)
2531+
ULONG n;
2532+
NTSTATUS status = NtQuerySystemInformation(
2533+
SystemProcessInformation,
2534+
unwinder->win_process_buffer,
2535+
unwinder->win_process_buffer_size,
2536+
&n
2537+
);
2538+
if (status == STATUS_INFO_LENGTH_MISMATCH) {
2539+
// Buffer was too small so we reallocate a larger one and try again.
2540+
unwinder->win_process_buffer_size = n;
2541+
PVOID new_buffer = PyMem_Realloc(unwinder->win_process_buffer, n);
2542+
if (!new_buffer) {
2543+
return -1;
2544+
}
2545+
unwinder->win_process_buffer = new_buffer;
2546+
return get_thread_status(unwinder, tid, pthread_id);
2547+
}
2548+
if (status != STATUS_SUCCESS) {
2549+
return -1;
2550+
}
2551+
2552+
SYSTEM_PROCESS_INFORMATION *pi = (SYSTEM_PROCESS_INFORMATION *)unwinder->win_process_buffer;
2553+
while ((ULONG)(ULONG_PTR)pi->UniqueProcessId != unwinder->handle.pid) {
2554+
if (pi->NextEntryOffset == 0) {
2555+
// We didn't find the process
2556+
return -1;
2557+
}
2558+
pi = (SYSTEM_PROCESS_INFORMATION *)(((BYTE *)pi) + pi->NextEntryOffset);
2559+
}
2560+
2561+
SYSTEM_THREAD_INFORMATION *ti = (SYSTEM_THREAD_INFORMATION *)((char *)pi + sizeof(SYSTEM_PROCESS_INFORMATION));
2562+
for (Py_ssize_t i = 0; i < pi->NumberOfThreads; i++, ti++) {
2563+
if (ti->ClientId.UniqueThread == (HANDLE)tid) {
2564+
return ti->ThreadState != WIN32_THREADSTATE_RUNNING ? THREAD_STATE_IDLE : THREAD_STATE_RUNNING;
2565+
}
2566+
}
2567+
2568+
return -1;
2569+
#else
2570+
return THREAD_STATE_UNKNOWN;
2571+
#endif
2572+
}
2573+
2574+
typedef struct {
2575+
unsigned int initialized:1;
2576+
unsigned int bound:1;
2577+
unsigned int unbound:1;
2578+
unsigned int bound_gilstate:1;
2579+
unsigned int active:1;
2580+
unsigned int finalizing:1;
2581+
unsigned int cleared:1;
2582+
unsigned int finalized:1;
2583+
unsigned int :24;
2584+
} _thread_status;
2585+
2586+
>>>>>>> Stashed changes
24562587
static PyObject*
24572588
unwind_stack_for_thread(
24582589
RemoteUnwinderObject *unwinder,

Python/remote_debug.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -891,7 +891,7 @@ _Py_RemoteDebug_GetPyRuntimeAddress(proc_handle_t* handle)
891891
handle->pid);
892892
_PyErr_ChainExceptions1(exc);
893893
}
894-
#elif defined(__linux__)
894+
#elif defined(__linux__) && HAVE_PROCESS_VM_READV
895895
// On Linux, search for 'python' in executable or DLL
896896
address = search_linux_map_for_section(handle, "PyRuntime", "python");
897897
if (address == 0) {

0 commit comments

Comments
 (0)