Skip to content

Commit 938b91c

Browse files
committed
Add fallback for when process_vm_readv fails with ENOSYS
1 parent e64395e commit 938b91c

File tree

3 files changed

+63
-0
lines changed

3 files changed

+63
-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: 34 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,37 @@ _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+
char mem_file_path[64];
960+
off_t offset = 0;
961+
sprintf(mem_file_path, "/proc/%d/mem", handle->pid);
962+
int fd = open(mem_file_path, O_RDONLY);
963+
if (fd == -1) {
964+
PyErr_SetFromErrno(PyExc_OSError);
965+
_set_debug_exception_cause(PyExc_OSError,
966+
"failed to open file %s: %s", mem_file_path, strerror(errno));
967+
return -1;
968+
}
969+
do {
970+
local[0].iov_base = (char*)dst + result;
971+
local[0].iov_len = len - result;
972+
offset = remote_address + result;
973+
974+
read_bytes = preadv(fd, local, 1, offset);
975+
if (read_bytes < 0) {
976+
PyErr_SetFromErrno(PyExc_OSError);
977+
_set_debug_exception_cause(PyExc_OSError,
978+
"readv failed for PID %d at address 0x%lx "
979+
"(size %zu, partial read %zd bytes): %s",
980+
handle->pid, remote_address + result, len - result, result, strerror(errno));
981+
close(fd);
982+
return -1;
983+
}
984+
985+
result += read_bytes;
986+
} while ((size_t)read_bytes != local[0].iov_len);
987+
close(fd);
988+
return 0;
955989
#elif defined(__APPLE__) && defined(TARGET_OS_OSX) && TARGET_OS_OSX
956990
Py_ssize_t result = -1;
957991
kern_return_t kr = mach_vm_read_overwrite(

Python/remote_debugging.c

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,13 +51,41 @@ 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+
char mem_file_path[64];
67+
off_t offset = 0;
68+
sprintf(mem_file_path, "/proc/%d/mem", handle->pid);
69+
int fd = open(mem_file_path, O_RDWR);
70+
if (fd == -1) {
71+
PyErr_SetFromErrno(PyExc_OSError);
72+
return -1;
73+
}
74+
do {
75+
local[0].iov_base = (void*)((char*)src + result);
76+
local[0].iov_len = len - result;
77+
offset = remote_address + result;
78+
79+
written = pwritev(fd, local, 1, offset);
5480
if (written < 0) {
5581
PyErr_SetFromErrno(PyExc_OSError);
82+
close(fd);
5683
return -1;
5784
}
5885

5986
result += written;
6087
} while ((size_t)written != local[0].iov_len);
88+
close(fd);
6189
return 0;
6290
#elif defined(__APPLE__) && TARGET_OS_OSX
6391
kern_return_t kr = mach_vm_write(

0 commit comments

Comments
 (0)