diff options
author | Pablo Galindo Salgado <Pablogsal@gmail.com> | 2025-04-25 14:12:16 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2025-04-25 14:12:16 +0100 |
commit | e8cf3a1a641d6fa0bfa84a4f8363ff1e42abda30 (patch) | |
tree | a16c74cc99357b235d6d685786dbcb7ed2422377 /Python/remote_debugging.c | |
parent | f6fb498c9759bc4ab615761639c5147d2d870c56 (diff) | |
download | cpython-e8cf3a1a641d6fa0bfa84a4f8363ff1e42abda30.tar.gz cpython-e8cf3a1a641d6fa0bfa84a4f8363ff1e42abda30.zip |
gh-91048: Refactor _testexternalinspection and add Windows support (#132852)
Diffstat (limited to 'Python/remote_debugging.c')
-rw-r--r-- | Python/remote_debugging.c | 749 |
1 files changed, 6 insertions, 743 deletions
diff --git a/Python/remote_debugging.c b/Python/remote_debugging.c index 9656297cb83..dd55b7812d4 100644 --- a/Python/remote_debugging.c +++ b/Python/remote_debugging.c @@ -5,754 +5,25 @@ #include "internal/pycore_runtime.h" #include "internal/pycore_ceval.h" -#ifdef __linux__ -# include <elf.h> -# include <sys/uio.h> -# if INTPTR_MAX == INT64_MAX -# define Elf_Ehdr Elf64_Ehdr -# define Elf_Shdr Elf64_Shdr -# define Elf_Phdr Elf64_Phdr -# else -# define Elf_Ehdr Elf32_Ehdr -# define Elf_Shdr Elf32_Shdr -# define Elf_Phdr Elf32_Phdr -# endif -# include <sys/mman.h> -#endif - -#if defined(__APPLE__) && TARGET_OS_OSX -# include <libproc.h> -# include <mach-o/fat.h> -# include <mach-o/loader.h> -# include <mach-o/nlist.h> -# include <mach/mach.h> -# include <mach/mach_vm.h> -# include <mach/machine.h> -# include <sys/mman.h> -# include <sys/proc.h> -# include <sys/sysctl.h> -#endif - -#ifdef MS_WINDOWS - // Windows includes and definitions -#include <windows.h> -#include <psapi.h> -#include <tlhelp32.h> -#endif - -#include <errno.h> -#include <fcntl.h> -#include <stddef.h> -#include <stdint.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#ifndef MS_WINDOWS -#include <sys/param.h> -#include <sys/stat.h> -#include <sys/types.h> -#include <unistd.h> -#endif - -#ifndef HAVE_PROCESS_VM_READV -# define HAVE_PROCESS_VM_READV 0 -#endif - #if defined(Py_REMOTE_DEBUG) && defined(Py_SUPPORTS_REMOTE_DEBUG) +#include "remote_debug.h" -// Define a platform-independent process handle structure -typedef struct { - pid_t pid; -#ifdef MS_WINDOWS - HANDLE hProcess; -#endif -} proc_handle_t; - -// Initialize the process handle static int init_proc_handle(proc_handle_t *handle, pid_t pid) { - handle->pid = pid; -#ifdef MS_WINDOWS - handle->hProcess = OpenProcess( - PROCESS_VM_READ | PROCESS_VM_WRITE | PROCESS_VM_OPERATION | PROCESS_QUERY_INFORMATION, - FALSE, pid); - if (handle->hProcess == NULL) { - PyErr_SetFromWindowsErr(0); - return -1; - } -#endif - return 0; + return _Py_RemoteDebug_InitProcHandle(handle, pid); } -// Clean up the process handle static void cleanup_proc_handle(proc_handle_t *handle) { -#ifdef MS_WINDOWS - if (handle->hProcess != NULL) { - CloseHandle(handle->hProcess); - handle->hProcess = NULL; - } -#endif - handle->pid = 0; -} - -#if defined(__APPLE__) && TARGET_OS_OSX -static uintptr_t -return_section_address64( - const char* section, - mach_port_t proc_ref, - uintptr_t base, - void* map -) { - struct mach_header_64* hdr = (struct mach_header_64*)map; - int ncmds = hdr->ncmds; - - int cmd_cnt = 0; - struct segment_command_64* cmd = map + sizeof(struct mach_header_64); - - mach_vm_size_t size = 0; - mach_msg_type_number_t count = sizeof(vm_region_basic_info_data_64_t); - mach_vm_address_t address = (mach_vm_address_t)base; - vm_region_basic_info_data_64_t r_info; - mach_port_t object_name; - uintptr_t vmaddr = 0; - - for (int i = 0; cmd_cnt < 2 && i < ncmds; i++) { - if (cmd->cmd == LC_SEGMENT_64 && strcmp(cmd->segname, "__TEXT") == 0) { - vmaddr = cmd->vmaddr; - } - if (cmd->cmd == LC_SEGMENT_64 && strcmp(cmd->segname, "__DATA") == 0) { - while (cmd->filesize != size) { - address += size; - kern_return_t ret = mach_vm_region( - proc_ref, - &address, - &size, - VM_REGION_BASIC_INFO_64, - (vm_region_info_t)&r_info, // cppcheck-suppress [uninitvar] - &count, - &object_name - ); - if (ret != KERN_SUCCESS) { - PyErr_SetString( - PyExc_RuntimeError, "Cannot get any more VM maps.\n"); - return 0; - } - } - - int nsects = cmd->nsects; - struct section_64* sec = (struct section_64*)( - (void*)cmd + sizeof(struct segment_command_64) - ); - for (int j = 0; j < nsects; j++) { - if (strcmp(sec[j].sectname, section) == 0) { - return base + sec[j].addr - vmaddr; - } - } - cmd_cnt++; - } - - cmd = (struct segment_command_64*)((void*)cmd + cmd->cmdsize); - } - - // We should not be here, but if we are there, we should say about this - PyErr_SetString( - PyExc_RuntimeError, "Cannot find section address.\n"); - return 0; -} - -static uintptr_t -return_section_address32( - const char* section, - mach_port_t proc_ref, - uintptr_t base, - void* map -) { - struct mach_header* hdr = (struct mach_header*)map; - int ncmds = hdr->ncmds; - - int cmd_cnt = 0; - struct segment_command* cmd = map + sizeof(struct mach_header); - - mach_vm_size_t size = 0; - mach_msg_type_number_t count = sizeof(vm_region_basic_info_data_t); - mach_vm_address_t address = (mach_vm_address_t)base; - vm_region_basic_info_data_t r_info; - mach_port_t object_name; - uintptr_t vmaddr = 0; - - for (int i = 0; cmd_cnt < 2 && i < ncmds; i++) { - if (cmd->cmd == LC_SEGMENT && strcmp(cmd->segname, "__TEXT") == 0) { - vmaddr = cmd->vmaddr; - } - if (cmd->cmd == LC_SEGMENT && strcmp(cmd->segname, "__DATA") == 0) { - while (cmd->filesize != size) { - address += size; - kern_return_t ret = mach_vm_region( - proc_ref, - &address, - &size, - VM_REGION_BASIC_INFO, - (vm_region_info_t)&r_info, // cppcheck-suppress [uninitvar] - &count, - &object_name - ); - if (ret != KERN_SUCCESS) { - PyErr_SetString( - PyExc_RuntimeError, "Cannot get any more VM maps.\n"); - return 0; - } - } - - int nsects = cmd->nsects; - struct section* sec = (struct section*)( - (void*)cmd + sizeof(struct segment_command) - ); - for (int j = 0; j < nsects; j++) { - if (strcmp(sec[j].sectname, section) == 0) { - return base + sec[j].addr - vmaddr; - } - } - cmd_cnt++; - } - - cmd = (struct segment_command*)((void*)cmd + cmd->cmdsize); - } - - // We should not be here, but if we are there, we should say about this - PyErr_SetString( - PyExc_RuntimeError, "Cannot find section address.\n"); - return 0; -} - -static uintptr_t -return_section_address_fat( - const char* section, - mach_port_t proc_ref, - uintptr_t base, - void* map -) { - struct fat_header* fat_hdr = (struct fat_header*)map; - - // Determine host CPU type for architecture selection - cpu_type_t cpu; - int is_abi64; - size_t cpu_size = sizeof(cpu), abi64_size = sizeof(is_abi64); - - sysctlbyname("hw.cputype", &cpu, &cpu_size, NULL, 0); - sysctlbyname("hw.cpu64bit_capable", &is_abi64, &abi64_size, NULL, 0); - - cpu |= is_abi64 * CPU_ARCH_ABI64; - - // Check endianness - int swap = fat_hdr->magic == FAT_CIGAM; - struct fat_arch* arch = (struct fat_arch*)(map + sizeof(struct fat_header)); - - // Get number of architectures in fat binary - uint32_t nfat_arch = swap ? __builtin_bswap32(fat_hdr->nfat_arch) : fat_hdr->nfat_arch; - - // Search for matching architecture - for (uint32_t i = 0; i < nfat_arch; i++) { - cpu_type_t arch_cpu = swap ? __builtin_bswap32(arch[i].cputype) : arch[i].cputype; - - if (arch_cpu == cpu) { - // Found matching architecture, now process it - uint32_t offset = swap ? __builtin_bswap32(arch[i].offset) : arch[i].offset; - struct mach_header_64* hdr = (struct mach_header_64*)(map + offset); - - // Determine which type of Mach-O it is and process accordingly - switch (hdr->magic) { - case MH_MAGIC: - case MH_CIGAM: - return return_section_address32(section, proc_ref, base, (void*)hdr); - - case MH_MAGIC_64: - case MH_CIGAM_64: - return return_section_address64(section, proc_ref, base, (void*)hdr); - - default: - PyErr_SetString(PyExc_RuntimeError, "Unknown Mach-O magic in fat binary.\n"); - return 0; - } - } - } - - PyErr_SetString(PyExc_RuntimeError, "No matching architecture found in fat binary.\n"); - return 0; -} - -static uintptr_t -search_section_in_file(const char* secname, char* path, uintptr_t base, mach_vm_size_t size, mach_port_t proc_ref) -{ - int fd = open(path, O_RDONLY); - if (fd == -1) { - PyErr_Format(PyExc_RuntimeError, "Cannot open binary %s\n", path); - return 0; - } - - struct stat fs; - if (fstat(fd, &fs) == -1) { - PyErr_Format(PyExc_RuntimeError, "Cannot get size of binary %s\n", path); - close(fd); - return 0; - } - - void* map = mmap(0, fs.st_size, PROT_READ, MAP_SHARED, fd, 0); - if (map == MAP_FAILED) { - PyErr_Format(PyExc_RuntimeError, "Cannot map binary %s\n", path); - close(fd); - return 0; - } - - uintptr_t result = 0; - uint32_t magic = *(uint32_t*)map; - - switch (magic) { - case MH_MAGIC: - case MH_CIGAM: - result = return_section_address32(secname, proc_ref, base, map); - break; - case MH_MAGIC_64: - case MH_CIGAM_64: - result = return_section_address64(secname, proc_ref, base, map); - break; - case FAT_MAGIC: - case FAT_CIGAM: - result = return_section_address_fat(secname, proc_ref, base, map); - break; - default: - PyErr_SetString(PyExc_RuntimeError, "Unknown Mach-O magic"); - break; - } - - munmap(map, fs.st_size); - if (close(fd) != 0) { - PyErr_SetFromErrno(PyExc_OSError); - } - return result; -} - -static mach_port_t -pid_to_task(pid_t pid) -{ - mach_port_t task; - kern_return_t result; - - result = task_for_pid(mach_task_self(), pid, &task); - if (result != KERN_SUCCESS) { - PyErr_Format(PyExc_PermissionError, "Cannot get task for PID %d", pid); - return 0; - } - return task; -} - -static uintptr_t -search_map_for_section(proc_handle_t *handle, const char* secname, const char* substr) { - mach_vm_address_t address = 0; - mach_vm_size_t size = 0; - mach_msg_type_number_t count = sizeof(vm_region_basic_info_data_64_t); - vm_region_basic_info_data_64_t region_info; - mach_port_t object_name; - - mach_port_t proc_ref = pid_to_task(handle->pid); - if (proc_ref == 0) { - PyErr_SetString(PyExc_PermissionError, "Cannot get task for PID"); - return 0; - } - - int match_found = 0; - char map_filename[MAXPATHLEN + 1]; - while (mach_vm_region( - proc_ref, - &address, - &size, - VM_REGION_BASIC_INFO_64, - (vm_region_info_t)®ion_info, - &count, - &object_name) == KERN_SUCCESS) - { - if ((region_info.protection & VM_PROT_READ) == 0 - || (region_info.protection & VM_PROT_EXECUTE) == 0) { - address += size; - continue; - } - - int path_len = proc_regionfilename( - handle->pid, address, map_filename, MAXPATHLEN); - if (path_len == 0) { - address += size; - continue; - } - - char* filename = strrchr(map_filename, '/'); - if (filename != NULL) { - filename++; // Move past the '/' - } else { - filename = map_filename; // No path, use the whole string - } - - if (!match_found && strncmp(filename, substr, strlen(substr)) == 0) { - match_found = 1; - return search_section_in_file( - secname, map_filename, address, size, proc_ref); - } - - address += size; - } - - PyErr_SetString(PyExc_RuntimeError, - "mach_vm_region failed to find the section"); - return 0; + _Py_RemoteDebug_CleanupProcHandle(handle); } -#endif // (__APPLE__ && TARGET_OS_OSX) - -#if defined(__linux__) && HAVE_PROCESS_VM_READV -static uintptr_t -search_elf_file_for_section( - proc_handle_t *handle, - const char* secname, - uintptr_t start_address, - const char *elf_file) -{ - if (start_address == 0) { - return 0; - } - - uintptr_t result = 0; - void* file_memory = NULL; - - int fd = open(elf_file, O_RDONLY); - if (fd < 0) { - PyErr_SetFromErrno(PyExc_OSError); - goto exit; - } - - struct stat file_stats; - if (fstat(fd, &file_stats) != 0) { - PyErr_SetFromErrno(PyExc_OSError); - goto exit; - } - - file_memory = mmap(NULL, file_stats.st_size, PROT_READ, MAP_PRIVATE, fd, 0); - if (file_memory == MAP_FAILED) { - PyErr_SetFromErrno(PyExc_OSError); - goto exit; - } - - Elf_Ehdr* elf_header = (Elf_Ehdr*)file_memory; - - Elf_Shdr* section_header_table = (Elf_Shdr*)(file_memory + elf_header->e_shoff); - - Elf_Shdr* shstrtab_section = §ion_header_table[elf_header->e_shstrndx]; - char* shstrtab = (char*)(file_memory + shstrtab_section->sh_offset); - - Elf_Shdr* section = NULL; - for (int i = 0; i < elf_header->e_shnum; i++) { - char* this_sec_name = shstrtab + section_header_table[i].sh_name; - // Move 1 character to account for the leading "." - this_sec_name += 1; - if (strcmp(secname, this_sec_name) == 0) { - section = §ion_header_table[i]; - break; - } - } - - Elf_Phdr* program_header_table = (Elf_Phdr*)(file_memory + elf_header->e_phoff); - // Find the first PT_LOAD segment - Elf_Phdr* first_load_segment = NULL; - for (int i = 0; i < elf_header->e_phnum; i++) { - if (program_header_table[i].p_type == PT_LOAD) { - first_load_segment = &program_header_table[i]; - break; - } - } - - if (section != NULL && first_load_segment != NULL) { - uintptr_t elf_load_addr = first_load_segment->p_vaddr - - (first_load_segment->p_vaddr % first_load_segment->p_align); - result = start_address + (uintptr_t)section->sh_addr - elf_load_addr; - } - -exit: - if (file_memory != NULL) { - munmap(file_memory, file_stats.st_size); - } - if (fd >= 0 && close(fd) != 0) { - PyErr_SetFromErrno(PyExc_OSError); - } - return result; -} - -static uintptr_t -search_linux_map_for_section(proc_handle_t *handle, const char* secname, const char* substr) -{ - char maps_file_path[64]; - sprintf(maps_file_path, "/proc/%d/maps", handle->pid); - - FILE* maps_file = fopen(maps_file_path, "r"); - if (maps_file == NULL) { - PyErr_SetFromErrno(PyExc_OSError); - return 0; - } - - size_t linelen = 0; - size_t linesz = PATH_MAX; - char *line = PyMem_Malloc(linesz); - if (!line) { - fclose(maps_file); - PyErr_NoMemory(); - return 0; - } - - uintptr_t retval = 0; - while (fgets(line + linelen, linesz - linelen, maps_file) != NULL) { - linelen = strlen(line); - if (line[linelen - 1] != '\n') { - // Read a partial line: realloc and keep reading where we left off. - // Note that even the last line will be terminated by a newline. - linesz *= 2; - char *biggerline = PyMem_Realloc(line, linesz); - if (!biggerline) { - PyMem_Free(line); - fclose(maps_file); - PyErr_NoMemory(); - return 0; - } - line = biggerline; - continue; - } - - // Read a full line: strip the newline - line[linelen - 1] = '\0'; - // and prepare to read the next line into the start of the buffer. - linelen = 0; - - unsigned long start = 0; - unsigned long path_pos = 0; - sscanf(line, "%lx-%*x %*s %*s %*s %*s %ln", &start, &path_pos); - - if (!path_pos) { - // Line didn't match our format string. This shouldn't be - // possible, but let's be defensive and skip the line. - continue; - } - - const char *path = line + path_pos; - const char *filename = strrchr(path, '/'); - if (filename) { - filename++; // Move past the '/' - } else { - filename = path; // No directories, or an empty string - } - - if (strstr(filename, substr)) { - retval = search_elf_file_for_section(handle, secname, start, path); - if (retval) { - break; - } - } - } - - PyMem_Free(line); - fclose(maps_file); - - return retval; -} - - -#endif // __linux__ - -#ifdef MS_WINDOWS - -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) { - PyErr_SetFromWindowsErr(0); - return NULL; - } - HANDLE hMap = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, 0); - if (!hMap) { - PyErr_SetFromWindowsErr(0); - CloseHandle(hFile); - return NULL; - } - - BYTE* mapView = (BYTE*)MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, 0); - if (!mapView) { - PyErr_SetFromWindowsErr(0); - CloseHandle(hMap); - CloseHandle(hFile); - return NULL; - } - - IMAGE_DOS_HEADER* pDOSHeader = (IMAGE_DOS_HEADER*)mapView; - if (pDOSHeader->e_magic != IMAGE_DOS_SIGNATURE) { - PyErr_SetString(PyExc_RuntimeError, "Invalid DOS signature."); - UnmapViewOfFile(mapView); - CloseHandle(hMap); - CloseHandle(hFile); - return NULL; - } - - IMAGE_NT_HEADERS* pNTHeaders = (IMAGE_NT_HEADERS*)(mapView + pDOSHeader->e_lfanew); - if (pNTHeaders->Signature != IMAGE_NT_SIGNATURE) { - PyErr_SetString(PyExc_RuntimeError, "Invalid NT signature."); - UnmapViewOfFile(mapView); - CloseHandle(hMap); - CloseHandle(hFile); - return NULL; - } - - IMAGE_SECTION_HEADER* pSection_header = (IMAGE_SECTION_HEADER*)(mapView + pDOSHeader->e_lfanew + sizeof(IMAGE_NT_HEADERS)); - void* runtime_addr = NULL; - - for (int i = 0; i < pNTHeaders->FileHeader.NumberOfSections; i++) { - const char* name = (const char*)pSection_header[i].Name; - if (strncmp(name, secname, IMAGE_SIZEOF_SHORT_NAME) == 0) { - runtime_addr = remote_base + pSection_header[i].VirtualAddress; - break; - } - } - - UnmapViewOfFile(mapView); - CloseHandle(hMap); - CloseHandle(hFile); - - return runtime_addr; -} - - -static uintptr_t -search_windows_map_for_section(proc_handle_t* handle, const char* secname, const wchar_t* substr) { - HANDLE hProcSnap; - do { - hProcSnap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, handle->pid); - } while (hProcSnap == INVALID_HANDLE_VALUE && GetLastError() == ERROR_BAD_LENGTH); - - if (hProcSnap == INVALID_HANDLE_VALUE) { - PyErr_SetString(PyExc_PermissionError, "Unable to create module snapshot. Check permissions or PID."); - return 0; - } - - MODULEENTRY32W moduleEntry; - moduleEntry.dwSize = sizeof(moduleEntry); - void* runtime_addr = NULL; - - for (BOOL hasModule = Module32FirstW(hProcSnap, &moduleEntry); hasModule; hasModule = Module32NextW(hProcSnap, &moduleEntry)) { - // Look for either python executable or DLL - if (wcsstr(moduleEntry.szModule, substr)) { - runtime_addr = analyze_pe(moduleEntry.szExePath, moduleEntry.modBaseAddr, secname); - if (runtime_addr != NULL) { - break; - } - } - } - - CloseHandle(hProcSnap); - return (uintptr_t)runtime_addr; -} - -#endif // MS_WINDOWS - -// Get the PyRuntime section address for any platform -static uintptr_t -get_py_runtime(proc_handle_t* handle) -{ - uintptr_t address = 0; - -#ifdef MS_WINDOWS - // On Windows, search for 'python' in executable or DLL - address = search_windows_map_for_section(handle, "PyRuntime", L"python"); - if (address == 0) { - // Error out: 'python' substring covers both executable and DLL - PyErr_SetString(PyExc_RuntimeError, "Failed to find the PyRuntime section in the process."); - } -#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 - PyErr_SetString(PyExc_RuntimeError, "Failed to find the PyRuntime section in the process."); - } -#else - // On macOS, try libpython first, then fall back to python - address = search_map_for_section(handle, "PyRuntime", "libpython"); - if (address == 0) { - // TODO: Differentiate between not found and error - PyErr_Clear(); - address = search_map_for_section(handle, "PyRuntime", "python"); - } -#endif - - return address; -} - -// Platform-independent memory read function static int read_memory(proc_handle_t *handle, uint64_t remote_address, size_t len, void* dst) { -#ifdef MS_WINDOWS - SIZE_T read_bytes = 0; - SIZE_T result = 0; - do { - if (!ReadProcessMemory(handle->hProcess, (LPCVOID)(remote_address + result), (char*)dst + result, len - result, &read_bytes)) { - PyErr_SetFromWindowsErr(0); - return -1; - } - result += read_bytes; - } while (result < len); - return 0; -#elif defined(__linux__) && HAVE_PROCESS_VM_READV - struct iovec local[1]; - struct iovec remote[1]; - Py_ssize_t result = 0; - Py_ssize_t read_bytes = 0; - - do { - local[0].iov_base = (char*)dst + result; - local[0].iov_len = len - result; - remote[0].iov_base = (void*)(remote_address + result); - remote[0].iov_len = len - result; - - read_bytes = process_vm_readv(handle->pid, local, 1, remote, 1, 0); - if (read_bytes < 0) { - PyErr_SetFromErrno(PyExc_OSError); - return -1; - } - - result += read_bytes; - } while ((size_t)read_bytes != local[0].iov_len); - return 0; -#elif defined(__APPLE__) && TARGET_OS_OSX - Py_ssize_t result = -1; - kern_return_t kr = mach_vm_read_overwrite( - pid_to_task(handle->pid), - (mach_vm_address_t)remote_address, - len, - (mach_vm_address_t)dst, - (mach_vm_size_t*)&result); - - if (kr != KERN_SUCCESS) { - switch (kr) { - case KERN_PROTECTION_FAILURE: - PyErr_SetString(PyExc_PermissionError, "Not enough permissions to read memory"); - break; - case KERN_INVALID_ARGUMENT: - PyErr_SetString(PyExc_PermissionError, "Invalid argument to mach_vm_read_overwrite"); - break; - default: - PyErr_SetString(PyExc_RuntimeError, "Unknown error reading memory"); - } - return -1; - } - return 0; -#else - Py_UNREACHABLE(); -#endif + return _Py_RemoteDebug_ReadRemoteMemory(handle, remote_address, len, dst); } -// Platform-independent memory write function static int write_memory(proc_handle_t *handle, uintptr_t remote_address, size_t len, const void* src) { @@ -886,16 +157,7 @@ read_offsets( uintptr_t *runtime_start_address, _Py_DebugOffsets* debug_offsets ) { - *runtime_start_address = get_py_runtime(handle); - if (!*runtime_start_address) { - if (!PyErr_Occurred()) { - PyErr_SetString( - PyExc_RuntimeError, "Failed to get PyRuntime address"); - } - return -1; - } - size_t size = sizeof(struct _Py_DebugOffsets); - if (0 != read_memory(handle, *runtime_start_address, size, debug_offsets)) { + if (_Py_RemoteDebug_ReadDebugOffsets(handle, runtime_start_address, debug_offsets)) { return -1; } if (ensure_debug_offset_compatibility(debug_offsets)) { @@ -1097,3 +359,4 @@ _PySysRemoteDebug_SendExec(int pid, int tid, const char *debugger_script_path) return rc; #endif } + |