Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Chain exception to get more info
  • Loading branch information
sergey-miryanov committed Apr 25, 2025
commit 6a72bf9c24eca95ec44f41b816fe756734af7cf2
66 changes: 40 additions & 26 deletions Modules/_testexternalinspection.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,18 @@
# define HAVE_PROCESS_VM_READV 0
#endif

#ifdef CHAIN_EXCEPTIONS
#error "CHAIN_EXCEPTIONS should not be defined"
#endif

#define CHAIN_EXCEPTIONS(Type, Msg) \
Comment thread
sergey-miryanov marked this conversation as resolved.
Outdated
do { \
PyObject *exc = PyErr_GetRaisedException(); \
PyErr_SetString((Type), (Msg)); \
_PyErr_ChainExceptions1(exc); \
} while(0)


struct _Py_AsyncioModuleDebugOffsets {
struct _asyncio_task_object {
uint64_t size;
Expand Down Expand Up @@ -304,7 +316,7 @@ parse_task_name(
if ((flags & Py_TPFLAGS_LONG_SUBCLASS)) {
long res = read_py_long(handle, offsets, task_name_addr);
if (res == -1) {
PyErr_SetString(PyExc_RuntimeError, "Failed to get task name");
CHAIN_EXCEPTIONS(PyExc_RuntimeError, "Failed to get task name");
return NULL;
}
return PyUnicode_FromFormat("Task-%d", res);
Expand Down Expand Up @@ -1156,30 +1168,32 @@ get_all_awaited_by(PyObject* self, PyObject* args)
return 0;
}

PyObject *result = NULL;

uintptr_t runtime_start_addr = _Py_RemoteDebug_GetPyRuntimeAddress(handle);
if (runtime_start_addr == 0) {
if (!PyErr_Occurred()) {
PyErr_SetString(
PyExc_RuntimeError, "Failed to get .PyRuntime address");
}
return NULL;
goto result_err;
}
struct _Py_DebugOffsets local_debug_offsets;

if (_Py_RemoteDebug_ReadDebugOffsets(handle, &runtime_start_addr, &local_debug_offsets)) {
PyErr_SetString(PyExc_RuntimeError, "Failed to read debug offsets");
return NULL;
CHAIN_EXCEPTIONS(PyExc_RuntimeError, "Failed to read debug offsets");
goto result_err;
}

struct _Py_AsyncioModuleDebugOffsets local_async_debug;
if (read_async_debug(handle, &local_async_debug)) {
PyErr_SetString(PyExc_RuntimeError, "Failed to read asyncio debug offsets");
return NULL;
CHAIN_EXCEPTIONS(PyExc_RuntimeError, "Failed to read asyncio debug offsets");
goto result_err;
}

PyObject *result = PyList_New(0);
result = PyList_New(0);
if (result == NULL) {
return NULL;
goto result_err;
}

uint64_t interpreter_state_list_head =
Expand Down Expand Up @@ -1256,7 +1270,7 @@ get_all_awaited_by(PyObject* self, PyObject* args)
return result;

result_err:
Py_DECREF(result);
Py_XDECREF(result);
_Py_RemoteDebug_CleanupProcHandle(handle);
return NULL;
}
Expand Down Expand Up @@ -1296,7 +1310,7 @@ get_stack_trace(PyObject* self, PyObject* args)
struct _Py_DebugOffsets local_debug_offsets;

if (_Py_RemoteDebug_ReadDebugOffsets(handle, &runtime_start_address, &local_debug_offsets)) {
PyErr_SetString(PyExc_RuntimeError, "Failed to read debug offsets");
CHAIN_EXCEPTIONS(PyExc_RuntimeError, "Failed to read debug offsets");
goto result_err;
}

Expand Down Expand Up @@ -1354,48 +1368,48 @@ get_async_stack_trace(PyObject* self, PyObject* args)
return 0;
}

PyObject *result = NULL;

uintptr_t runtime_start_address = _Py_RemoteDebug_GetPyRuntimeAddress(handle);
if (runtime_start_address == 0) {
if (!PyErr_Occurred()) {
PyErr_SetString(
PyExc_RuntimeError, "Failed to get .PyRuntime address");
}
return NULL;
goto result_err;
}
struct _Py_DebugOffsets local_debug_offsets;

if (_Py_RemoteDebug_ReadDebugOffsets(handle, &runtime_start_address, &local_debug_offsets)) {
PyErr_SetString(PyExc_RuntimeError, "Failed to read debug offsets");
return NULL;
CHAIN_EXCEPTIONS(PyExc_RuntimeError, "Failed to read debug offsets");
goto result_err;
}

struct _Py_AsyncioModuleDebugOffsets local_async_debug;
if (read_async_debug(handle, &local_async_debug)) {
PyErr_SetString(PyExc_RuntimeError, "Failed to read asyncio debug offsets");
return NULL;
CHAIN_EXCEPTIONS(PyExc_RuntimeError, "Failed to read asyncio debug offsets");
goto result_err;
}

PyObject* result = PyList_New(1);
result = PyList_New(1);
if (result == NULL) {
return NULL;
goto result_err;
}
PyObject* calls = PyList_New(0);
if (calls == NULL) {
Py_DECREF(result);
return NULL;
goto result_err;
}
if (PyList_SetItem(result, 0, calls)) { /* steals ref to 'calls' */
Py_DECREF(result);
Py_DECREF(calls);
return NULL;
goto result_err;
}

uintptr_t running_task_addr = (uintptr_t)NULL;
if (find_running_task(
handle, runtime_start_address, &local_debug_offsets, &local_async_debug,
&running_task_addr)
) {
PyErr_SetString(PyExc_RuntimeError, "Failed to find running task");
CHAIN_EXCEPTIONS(PyExc_RuntimeError, "Failed to find running task");
goto result_err;
}

Expand All @@ -1410,7 +1424,7 @@ get_async_stack_trace(PyObject* self, PyObject* args)
running_task_addr + local_async_debug.asyncio_task_object.task_coro,
&running_coro_addr
)) {
PyErr_SetString(PyExc_RuntimeError, "Failed to read running task coro");
CHAIN_EXCEPTIONS(PyExc_RuntimeError, "Failed to read running task coro");
goto result_err;
}

Expand Down Expand Up @@ -1440,7 +1454,7 @@ get_async_stack_trace(PyObject* self, PyObject* args)
handle, runtime_start_address, &local_debug_offsets,
&address_of_current_frame)
) {
PyErr_SetString(PyExc_RuntimeError, "Failed to find running frame");
CHAIN_EXCEPTIONS(PyExc_RuntimeError, "Failed to find running frame");
goto result_err;
}

Expand All @@ -1456,7 +1470,7 @@ get_async_stack_trace(PyObject* self, PyObject* args)
);

if (res < 0) {
PyErr_SetString(PyExc_RuntimeError, "Failed to parse async frame object");
CHAIN_EXCEPTIONS(PyExc_RuntimeError, "Failed to parse async frame object");
goto result_err;
}

Expand Down Expand Up @@ -1498,7 +1512,7 @@ get_async_stack_trace(PyObject* self, PyObject* args)

result_err:
_Py_RemoteDebug_CleanupProcHandle(handle);
Py_DECREF(result);
Py_XDECREF(result);
return NULL;
}

Expand Down
9 changes: 9 additions & 0 deletions Python/remote_debug.h
Original file line number Diff line number Diff line change
Expand Up @@ -688,14 +688,18 @@ _Py_RemoteDebug_GetPyRuntimeAddress(proc_handle_t* handle)
address = search_windows_map_for_section(handle, "PyRuntime", L"python");
if (address == 0) {
// Error out: 'python' substring covers both executable and DLL
PyObject *exc = PyErr_GetRaisedException();
PyErr_SetString(PyExc_RuntimeError, "Failed to find the PyRuntime section in the process.");
_PyErr_ChainExceptions1(exc);
}
#elif defined(__linux__)
// On Linux, search for 'python' in executable or DLL
address = search_linux_map_for_section(handle, "PyRuntime", "python");
if (address == 0) {
// Error out: 'python' substring covers both executable and DLL
PyObject *exc = PyErr_GetRaisedException();
PyErr_SetString(PyExc_RuntimeError, "Failed to find the PyRuntime section in the process.");
_PyErr_ChainExceptions1(exc);
}
#elif defined(__APPLE__) && TARGET_OS_OSX
// On macOS, try libpython first, then fall back to python
Expand All @@ -704,6 +708,11 @@ _Py_RemoteDebug_GetPyRuntimeAddress(proc_handle_t* handle)
// TODO: Differentiate between not found and error
PyErr_Clear();
address = search_map_for_section(handle, "PyRuntime", "python");
if (address == 0) {
PyObject *exc = PyErr_GetRaisedException();
PyErr_SetString(PyExc_RuntimeError, "Failed to find the PyRuntime section in the process.");
_PyErr_ChainExceptions1(exc);
}
}
#else
Py_UNREACHABLE();
Expand Down
Loading