Skip to content

Commit 90b08e6

Browse files
committed
Add fallback for when process_vm_readv fails with ENOSYS
1 parent e64395e commit 90b08e6

File tree

3 files changed

+65
-0
lines changed

3 files changed

+65
-0
lines changed

Misc/ACKS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -658,6 +658,7 @@ Michael Goderbauer
658658
Karan Goel
659659
Jeroen Van Goey
660660
Christoph Gohlke
661+
Daniel Golding
661662
Tim Golden
662663
Yonatan Goldschmidt
663664
Mark Gollahon

Python/remote_debug.h

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -941,6 +941,9 @@ _Py_RemoteDebug_ReadRemoteMemory(proc_handle_t *handle, uintptr_t remote_address
941941

942942
read_bytes = process_vm_readv(handle->pid, local, 1, remote, 1, 0);
943943
if (read_bytes < 0) {
944+
if (errno == ENOSYS) {
945+
goto fallback;
946+
}
944947
PyErr_SetFromErrno(PyExc_OSError);
945948
_set_debug_exception_cause(PyExc_OSError,
946949
"process_vm_readv failed for PID %d at address 0x%lx "
@@ -952,6 +955,38 @@ _Py_RemoteDebug_ReadRemoteMemory(proc_handle_t *handle, uintptr_t remote_address
952955
result += read_bytes;
953956
} while ((size_t)read_bytes != local[0].iov_len);
954957
return 0;
958+
fallback:
959+
; // statement after label needed by gcc 10 and earlier
960+
char mem_file_path[64];
961+
off_t offset = 0;
962+
sprintf(mem_file_path, "/proc/%d/mem", handle->pid);
963+
int fd = open(mem_file_path, O_RDONLY);
964+
if (fd == -1) {
965+
PyErr_SetFromErrno(PyExc_OSError);
966+
_set_debug_exception_cause(PyExc_OSError,
967+
"failed to open file %s: %s", mem_file_path, strerror(errno));
968+
return -1;
969+
}
970+
do {
971+
local[0].iov_base = (char*)dst + result;
972+
local[0].iov_len = len - result;
973+
offset = remote_address + result;
974+
975+
read_bytes = preadv(fd, local, 1, offset);
976+
if (read_bytes < 0) {
977+
PyErr_SetFromErrno(PyExc_OSError);
978+
_set_debug_exception_cause(PyExc_OSError,
979+
"readv failed for PID %d at address 0x%lx "
980+
"(size %zu, partial read %zd bytes): %s",
981+
handle->pid, remote_address + result, len - result, result, strerror(errno));
982+
close(fd);
983+
return -1;
984+
}
985+
986+
result += read_bytes;
987+
} while ((size_t)read_bytes != local[0].iov_len);
988+
close(fd);
989+
return 0;
955990
#elif defined(__APPLE__) && defined(TARGET_OS_OSX) && TARGET_OS_OSX
956991
Py_ssize_t result = -1;
957992
kern_return_t kr = mach_vm_read_overwrite(

Python/remote_debugging.c

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,13 +51,42 @@ write_memory(proc_handle_t *handle, uintptr_t remote_address, size_t len, const
5151
remote[0].iov_len = len - result;
5252

5353
written = process_vm_writev(handle->pid, local, 1, remote, 1, 0);
54+
if (written < 0) {
55+
if (errno == ENOSYS) {
56+
goto fallback;
57+
}
58+
PyErr_SetFromErrno(PyExc_OSError);
59+
return -1;
60+
}
61+
62+
result += written;
63+
} while ((size_t)written != local[0].iov_len);
64+
return 0;
65+
fallback:
66+
; // statement after label needed by gcc 10 and earlier
67+
char mem_file_path[64];
68+
off_t offset = 0;
69+
sprintf(mem_file_path, "/proc/%d/mem", handle->pid);
70+
int fd = open(mem_file_path, O_RDWR);
71+
if (fd == -1) {
72+
PyErr_SetFromErrno(PyExc_OSError);
73+
return -1;
74+
}
75+
do {
76+
local[0].iov_base = (void*)((char*)src + result);
77+
local[0].iov_len = len - result;
78+
offset = remote_address + result;
79+
80+
written = pwritev(fd, local, 1, offset);
5481
if (written < 0) {
5582
PyErr_SetFromErrno(PyExc_OSError);
83+
close(fd);
5684
return -1;
5785
}
5886

5987
result += written;
6088
} while ((size_t)written != local[0].iov_len);
89+
close(fd);
6190
return 0;
6291
#elif defined(__APPLE__) && TARGET_OS_OSX
6392
kern_return_t kr = mach_vm_write(

0 commit comments

Comments
 (0)