Skip to content

Commit 22c9886

Browse files
authored
gh-131591: Implement PEP 768 support for FAT mac binaries and 32 bit binaries (#132892)
Signed-off-by: Pablo Galindo <[email protected]>
1 parent 797b29b commit 22c9886

File tree

1 file changed

+129
-7
lines changed

1 file changed

+129
-7
lines changed

Python/remote_debugging.c

Lines changed: 129 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ cleanup_proc_handle(proc_handle_t *handle) {
9898

9999
#if defined(__APPLE__) && TARGET_OS_OSX
100100
static uintptr_t
101-
return_section_address(
101+
return_section_address64(
102102
const char* section,
103103
mach_port_t proc_ref,
104104
uintptr_t base,
@@ -161,6 +161,126 @@ return_section_address(
161161
return 0;
162162
}
163163

164+
static uintptr_t
165+
return_section_address32(
166+
const char* section,
167+
mach_port_t proc_ref,
168+
uintptr_t base,
169+
void* map
170+
) {
171+
struct mach_header* hdr = (struct mach_header*)map;
172+
int ncmds = hdr->ncmds;
173+
174+
int cmd_cnt = 0;
175+
struct segment_command* cmd = map + sizeof(struct mach_header);
176+
177+
mach_vm_size_t size = 0;
178+
mach_msg_type_number_t count = sizeof(vm_region_basic_info_data_t);
179+
mach_vm_address_t address = (mach_vm_address_t)base;
180+
vm_region_basic_info_data_t r_info;
181+
mach_port_t object_name;
182+
uintptr_t vmaddr = 0;
183+
184+
for (int i = 0; cmd_cnt < 2 && i < ncmds; i++) {
185+
if (cmd->cmd == LC_SEGMENT && strcmp(cmd->segname, "__TEXT") == 0) {
186+
vmaddr = cmd->vmaddr;
187+
}
188+
if (cmd->cmd == LC_SEGMENT && strcmp(cmd->segname, "__DATA") == 0) {
189+
while (cmd->filesize != size) {
190+
address += size;
191+
kern_return_t ret = mach_vm_region(
192+
proc_ref,
193+
&address,
194+
&size,
195+
VM_REGION_BASIC_INFO,
196+
(vm_region_info_t)&r_info, // cppcheck-suppress [uninitvar]
197+
&count,
198+
&object_name
199+
);
200+
if (ret != KERN_SUCCESS) {
201+
PyErr_SetString(
202+
PyExc_RuntimeError, "Cannot get any more VM maps.\n");
203+
return 0;
204+
}
205+
}
206+
207+
int nsects = cmd->nsects;
208+
struct section* sec = (struct section*)(
209+
(void*)cmd + sizeof(struct segment_command)
210+
);
211+
for (int j = 0; j < nsects; j++) {
212+
if (strcmp(sec[j].sectname, section) == 0) {
213+
return base + sec[j].addr - vmaddr;
214+
}
215+
}
216+
cmd_cnt++;
217+
}
218+
219+
cmd = (struct segment_command*)((void*)cmd + cmd->cmdsize);
220+
}
221+
222+
// We should not be here, but if we are there, we should say about this
223+
PyErr_SetString(
224+
PyExc_RuntimeError, "Cannot find section address.\n");
225+
return 0;
226+
}
227+
228+
static uintptr_t
229+
return_section_address_fat(
230+
const char* section,
231+
mach_port_t proc_ref,
232+
uintptr_t base,
233+
void* map
234+
) {
235+
struct fat_header* fat_hdr = (struct fat_header*)map;
236+
237+
// Determine host CPU type for architecture selection
238+
cpu_type_t cpu;
239+
int is_abi64;
240+
size_t cpu_size = sizeof(cpu), abi64_size = sizeof(is_abi64);
241+
242+
sysctlbyname("hw.cputype", &cpu, &cpu_size, NULL, 0);
243+
sysctlbyname("hw.cpu64bit_capable", &is_abi64, &abi64_size, NULL, 0);
244+
245+
cpu |= is_abi64 * CPU_ARCH_ABI64;
246+
247+
// Check endianness
248+
int swap = fat_hdr->magic == FAT_CIGAM;
249+
struct fat_arch* arch = (struct fat_arch*)(map + sizeof(struct fat_header));
250+
251+
// Get number of architectures in fat binary
252+
uint32_t nfat_arch = swap ? __builtin_bswap32(fat_hdr->nfat_arch) : fat_hdr->nfat_arch;
253+
254+
// Search for matching architecture
255+
for (uint32_t i = 0; i < nfat_arch; i++) {
256+
cpu_type_t arch_cpu = swap ? __builtin_bswap32(arch[i].cputype) : arch[i].cputype;
257+
258+
if (arch_cpu == cpu) {
259+
// Found matching architecture, now process it
260+
uint32_t offset = swap ? __builtin_bswap32(arch[i].offset) : arch[i].offset;
261+
struct mach_header_64* hdr = (struct mach_header_64*)(map + offset);
262+
263+
// Determine which type of Mach-O it is and process accordingly
264+
switch (hdr->magic) {
265+
case MH_MAGIC:
266+
case MH_CIGAM:
267+
return return_section_address32(section, proc_ref, base, (void*)hdr);
268+
269+
case MH_MAGIC_64:
270+
case MH_CIGAM_64:
271+
return return_section_address64(section, proc_ref, base, (void*)hdr);
272+
273+
default:
274+
PyErr_SetString(PyExc_RuntimeError, "Unknown Mach-O magic in fat binary.\n");
275+
return 0;
276+
}
277+
}
278+
}
279+
280+
PyErr_SetString(PyExc_RuntimeError, "No matching architecture found in fat binary.\n");
281+
return 0;
282+
}
283+
164284
static uintptr_t
165285
search_section_in_file(const char* secname, char* path, uintptr_t base, mach_vm_size_t size, mach_port_t proc_ref)
166286
{
@@ -185,18 +305,20 @@ search_section_in_file(const char* secname, char* path, uintptr_t base, mach_vm_
185305
}
186306

187307
uintptr_t result = 0;
308+
uint32_t magic = *(uint32_t*)map;
188309

189-
struct mach_header_64* hdr = (struct mach_header_64*)map;
190-
switch (hdr->magic) {
310+
switch (magic) {
191311
case MH_MAGIC:
192312
case MH_CIGAM:
193-
case FAT_MAGIC:
194-
case FAT_CIGAM:
195-
PyErr_SetString(PyExc_RuntimeError, "32-bit Mach-O binaries are not supported");
313+
result = return_section_address32(secname, proc_ref, base, map);
196314
break;
197315
case MH_MAGIC_64:
198316
case MH_CIGAM_64:
199-
result = return_section_address(secname, proc_ref, base, map);
317+
result = return_section_address64(secname, proc_ref, base, map);
318+
break;
319+
case FAT_MAGIC:
320+
case FAT_CIGAM:
321+
result = return_section_address_fat(secname, proc_ref, base, map);
200322
break;
201323
default:
202324
PyErr_SetString(PyExc_RuntimeError, "Unknown Mach-O magic");

0 commit comments

Comments
 (0)