winex11.drv: Ignore .dwAspect in FORMATETC during XDnD.
[wine.git] / dlls / dbghelp / macho_module.c
blobf957439d435dfb147b607ddd795950cd812c437b
1 /*
2 * File macho_module.c - processing of Mach-O files
3 * Originally based on elf_module.c
5 * Copyright (C) 1996, Eric Youngdale.
6 * 1999-2007 Eric Pouech
7 * 2009 Ken Thomases, CodeWeavers Inc.
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24 #include "config.h"
25 #include "wine/port.h"
27 #ifdef HAVE_MACH_O_LOADER_H
28 #include <CoreFoundation/CFString.h>
29 #define LoadResource mac_LoadResource
30 #define GetCurrentThread mac_GetCurrentThread
31 #include <CoreServices/CoreServices.h>
32 #undef LoadResource
33 #undef GetCurrentThread
34 #endif
36 #include <stdio.h>
37 #include <assert.h>
38 #include <stdarg.h>
39 #include <errno.h>
40 #ifdef HAVE_SYS_STAT_H
41 # include <sys/stat.h>
42 #endif
43 #ifdef HAVE_SYS_MMAN_H
44 # include <sys/mman.h>
45 #endif
47 #include "ntstatus.h"
48 #define WIN32_NO_STATUS
49 #include "dbghelp_private.h"
50 #include "winternl.h"
51 #include "wine/library.h"
52 #include "wine/debug.h"
53 #include "wine/heap.h"
54 #include "image_private.h"
56 #ifdef HAVE_MACH_O_LOADER_H
58 #include <mach-o/fat.h>
59 #include <mach-o/loader.h>
60 #include <mach-o/nlist.h>
61 #include <mach-o/dyld.h>
63 struct dyld_image_info32 {
64 uint32_t /* const struct mach_header* */ imageLoadAddress;
65 uint32_t /* const char* */ imageFilePath;
66 uint32_t /* uintptr_t */ imageFileModDate;
69 struct dyld_all_image_infos32 {
70 uint32_t version;
71 uint32_t infoArrayCount;
72 uint32_t /* const struct dyld_image_info* */ infoArray;
75 struct dyld_image_info64 {
76 uint64_t /* const struct mach_header* */ imageLoadAddress;
77 uint64_t /* const char* */ imageFilePath;
78 uint64_t /* uintptr_t */ imageFileModDate;
81 struct dyld_all_image_infos64 {
82 uint32_t version;
83 uint32_t infoArrayCount;
84 uint64_t /* const struct dyld_image_info* */ infoArray;
87 union wine_image_info {
88 struct dyld_image_info32 info32;
89 struct dyld_image_info64 info64;
92 union wine_all_image_infos {
93 struct dyld_all_image_infos32 infos32;
94 struct dyld_all_image_infos64 infos64;
97 #ifdef WORDS_BIGENDIAN
98 #define swap_ulong_be_to_host(n) (n)
99 #else
100 #define swap_ulong_be_to_host(n) (RtlUlongByteSwap(n))
101 #endif
103 WINE_DEFAULT_DEBUG_CHANNEL(dbghelp_macho);
106 /* Bitmask for Mach-O image header flags indicating that the image is in dyld's
107 shared cached. That implies that its segments are mapped non-contiguously.
108 This value isn't defined anywhere in headers. It's used in dyld and in
109 debuggers which support OS X as a magic number.
111 The flag also isn't set in the on-disk image file. It's only set in
112 memory by dyld. */
113 #define MACHO_DYLD_IN_SHARED_CACHE 0x80000000
116 #define UUID_STRING_LEN 37 /* 16 bytes at 2 hex digits apiece, 4 dashes, and the null terminator */
119 struct macho_module_info
121 struct image_file_map file_map;
122 unsigned long load_addr;
123 unsigned short in_use : 1,
124 is_loader : 1;
127 struct section_info
129 BOOL split_segs;
130 unsigned int section_index;
133 #define MACHO_INFO_DEBUG_HEADER 0x0001
134 #define MACHO_INFO_MODULE 0x0002
135 #define MACHO_INFO_NAME 0x0004
137 struct macho_info
139 unsigned flags; /* IN one (or several) of the MACHO_INFO constants */
140 unsigned long dbg_hdr_addr; /* OUT address of debug header (if MACHO_INFO_DEBUG_HEADER is set) */
141 struct module* module; /* OUT loaded module (if MACHO_INFO_MODULE is set) */
142 const WCHAR* module_name; /* OUT found module name (if MACHO_INFO_NAME is set) */
145 static void macho_unmap_file(struct image_file_map* fmap);
147 static char* format_uuid(const uint8_t uuid[16], char out[UUID_STRING_LEN])
149 sprintf(out, "%02X%02X%02X%02X-%02X%02X-%02X%02X-%02X%02X-%02X%02X%02X%02X%02X%02X",
150 uuid[0], uuid[1], uuid[2], uuid[3], uuid[4], uuid[5], uuid[6], uuid[7],
151 uuid[8], uuid[9], uuid[10], uuid[11], uuid[12], uuid[13], uuid[14], uuid[15]);
152 return out;
155 /******************************************************************
156 * macho_calc_range
158 * For a range (offset & length) of a single architecture within
159 * a Mach-O file, calculate the page-aligned range of the whole file
160 * that encompasses it. For a fat binary, the architecture will
161 * itself be offset within the file, so take that into account.
163 static void macho_calc_range(const struct macho_file_map* fmap, unsigned long offset,
164 unsigned long len, unsigned long* out_aligned_offset,
165 unsigned long* out_aligned_end, unsigned long* out_aligned_len,
166 unsigned long* out_misalign)
168 unsigned long pagemask = sysconf( _SC_PAGESIZE ) - 1;
169 unsigned long file_offset, misalign;
171 file_offset = fmap->arch_offset + offset;
172 misalign = file_offset & pagemask;
173 *out_aligned_offset = file_offset - misalign;
174 *out_aligned_end = (file_offset + len + pagemask) & ~pagemask;
175 if (out_aligned_len)
176 *out_aligned_len = *out_aligned_end - *out_aligned_offset;
177 if (out_misalign)
178 *out_misalign = misalign;
181 /******************************************************************
182 * macho_map_range
184 * Maps a range (offset, length in bytes) from a Mach-O file into memory
186 static const char* macho_map_range(const struct macho_file_map* fmap, unsigned long offset, unsigned long len,
187 const char** base)
189 unsigned long misalign, aligned_offset, aligned_map_end, map_size;
190 const void* aligned_ptr;
192 TRACE("(%p/%d, 0x%08lx, 0x%08lx)\n", fmap, fmap->fd, offset, len);
194 macho_calc_range(fmap, offset, len, &aligned_offset, &aligned_map_end,
195 &map_size, &misalign);
197 aligned_ptr = mmap(NULL, map_size, PROT_READ, MAP_PRIVATE, fmap->fd, aligned_offset);
199 TRACE("Mapped (0x%08lx - 0x%08lx) to %p\n", aligned_offset, aligned_map_end, aligned_ptr);
201 if (aligned_ptr == MAP_FAILED) return IMAGE_NO_MAP;
202 if (base)
203 *base = aligned_ptr;
204 return (const char*)aligned_ptr + misalign;
207 /******************************************************************
208 * macho_unmap_range
210 * Unmaps a range (offset, length in bytes) of a Mach-O file from memory
212 static void macho_unmap_range(const char** base, const void** mapped, const struct macho_file_map* fmap,
213 unsigned long offset, unsigned long len)
215 TRACE("(%p, %p, %p/%d, 0x%08lx, 0x%08lx)\n", base, mapped, fmap, fmap->fd, offset, len);
217 if ((mapped && *mapped != IMAGE_NO_MAP) || (base && *base != IMAGE_NO_MAP))
219 unsigned long misalign, aligned_offset, aligned_map_end, map_size;
220 void* aligned_ptr;
222 macho_calc_range(fmap, offset, len, &aligned_offset, &aligned_map_end,
223 &map_size, &misalign);
225 if (mapped)
226 aligned_ptr = (char*)*mapped - misalign;
227 else
228 aligned_ptr = (void*)*base;
229 if (munmap(aligned_ptr, map_size) < 0)
230 WARN("Couldn't unmap the range\n");
231 TRACE("Unmapped (0x%08lx - 0x%08lx) from %p - %p\n", aligned_offset, aligned_map_end, aligned_ptr, (char*)aligned_ptr + map_size);
232 if (mapped)
233 *mapped = IMAGE_NO_MAP;
234 if (base)
235 *base = IMAGE_NO_MAP;
239 /******************************************************************
240 * macho_map_ranges
242 * Maps two ranges (offset, length in bytes) from a Mach-O file
243 * into memory. If the two ranges overlap, use one mmap so that
244 * the munmap doesn't fragment the mapping.
246 static BOOL macho_map_ranges(const struct macho_file_map* fmap,
247 unsigned long offset1, unsigned long len1,
248 unsigned long offset2, unsigned long len2,
249 const void** mapped1, const void** mapped2)
251 unsigned long aligned_offset1, aligned_map_end1;
252 unsigned long aligned_offset2, aligned_map_end2;
254 TRACE("(%p/%d, 0x%08lx, 0x%08lx, 0x%08lx, 0x%08lx, %p, %p)\n", fmap, fmap->fd,
255 offset1, len1, offset2, len2, mapped1, mapped2);
257 macho_calc_range(fmap, offset1, len1, &aligned_offset1, &aligned_map_end1, NULL, NULL);
258 macho_calc_range(fmap, offset2, len2, &aligned_offset2, &aligned_map_end2, NULL, NULL);
260 if (aligned_map_end1 < aligned_offset2 || aligned_map_end2 < aligned_offset1)
262 *mapped1 = macho_map_range(fmap, offset1, len1, NULL);
263 if (*mapped1 != IMAGE_NO_MAP)
265 *mapped2 = macho_map_range(fmap, offset2, len2, NULL);
266 if (*mapped2 == IMAGE_NO_MAP)
267 macho_unmap_range(NULL, mapped1, fmap, offset1, len1);
270 else
272 if (offset1 < offset2)
274 *mapped1 = macho_map_range(fmap, offset1, offset2 + len2 - offset1, NULL);
275 if (*mapped1 != IMAGE_NO_MAP)
276 *mapped2 = (const char*)*mapped1 + offset2 - offset1;
278 else
280 *mapped2 = macho_map_range(fmap, offset2, offset1 + len1 - offset2, NULL);
281 if (*mapped2 != IMAGE_NO_MAP)
282 *mapped1 = (const char*)*mapped2 + offset1 - offset2;
286 TRACE(" => %p, %p\n", *mapped1, *mapped2);
288 return (*mapped1 != IMAGE_NO_MAP) && (*mapped2 != IMAGE_NO_MAP);
291 /******************************************************************
292 * macho_unmap_ranges
294 * Unmaps two ranges (offset, length in bytes) of a Mach-O file
295 * from memory. Use for ranges which were mapped by
296 * macho_map_ranges.
298 static void macho_unmap_ranges(const struct macho_file_map* fmap,
299 unsigned long offset1, unsigned long len1,
300 unsigned long offset2, unsigned long len2,
301 const void** mapped1, const void** mapped2)
303 unsigned long aligned_offset1, aligned_map_end1;
304 unsigned long aligned_offset2, aligned_map_end2;
306 TRACE("(%p/%d, 0x%08lx, 0x%08lx, 0x%08lx, 0x%08lx, %p/%p, %p/%p)\n", fmap, fmap->fd,
307 offset1, len1, offset2, len2, mapped1, *mapped1, mapped2, *mapped2);
309 macho_calc_range(fmap, offset1, len1, &aligned_offset1, &aligned_map_end1, NULL, NULL);
310 macho_calc_range(fmap, offset2, len2, &aligned_offset2, &aligned_map_end2, NULL, NULL);
312 if (aligned_map_end1 < aligned_offset2 || aligned_map_end2 < aligned_offset1)
314 macho_unmap_range(NULL, mapped1, fmap, offset1, len1);
315 macho_unmap_range(NULL, mapped2, fmap, offset2, len2);
317 else
319 if (offset1 < offset2)
321 macho_unmap_range(NULL, mapped1, fmap, offset1, offset2 + len2 - offset1);
322 *mapped2 = IMAGE_NO_MAP;
324 else
326 macho_unmap_range(NULL, mapped2, fmap, offset2, offset1 + len1 - offset2);
327 *mapped1 = IMAGE_NO_MAP;
332 /******************************************************************
333 * macho_find_section
335 BOOL macho_find_section(struct image_file_map* ifm, const char* segname, const char* sectname, struct image_section_map* ism)
337 struct macho_file_map* fmap;
338 unsigned i;
339 char tmp[sizeof(fmap->sect[0].section.sectname)];
341 /* Other parts of dbghelp use section names like ".eh_frame". Mach-O uses
342 names like "__eh_frame". Convert those. */
343 if (sectname[0] == '.')
345 lstrcpynA(tmp, "__", sizeof(tmp));
346 lstrcpynA(tmp + 2, sectname + 1, sizeof(tmp) - 2);
347 sectname = tmp;
350 while (ifm)
352 fmap = &ifm->u.macho;
353 for (i = 0; i < fmap->num_sections; i++)
355 if (!fmap->sect[i].ignored &&
356 strcmp(fmap->sect[i].section.sectname, sectname) == 0 &&
357 (!segname || strcmp(fmap->sect[i].section.segname, segname) == 0))
359 ism->fmap = ifm;
360 ism->sidx = i;
361 return TRUE;
364 ifm = fmap->dsym;
367 ism->fmap = NULL;
368 ism->sidx = -1;
369 return FALSE;
372 /******************************************************************
373 * macho_map_section
375 const char* macho_map_section(struct image_section_map* ism)
377 struct macho_file_map* fmap = &ism->fmap->u.macho;
379 assert(ism->fmap->modtype == DMT_MACHO);
380 if (ism->sidx < 0 || ism->sidx >= ism->fmap->u.macho.num_sections || fmap->sect[ism->sidx].ignored)
381 return IMAGE_NO_MAP;
383 return macho_map_range(fmap, fmap->sect[ism->sidx].section.offset, fmap->sect[ism->sidx].section.size,
384 &fmap->sect[ism->sidx].mapped);
387 /******************************************************************
388 * macho_unmap_section
390 void macho_unmap_section(struct image_section_map* ism)
392 struct macho_file_map* fmap = &ism->fmap->u.macho;
394 if (ism->sidx >= 0 && ism->sidx < fmap->num_sections && fmap->sect[ism->sidx].mapped != IMAGE_NO_MAP)
396 macho_unmap_range(&fmap->sect[ism->sidx].mapped, NULL, fmap, fmap->sect[ism->sidx].section.offset,
397 fmap->sect[ism->sidx].section.size);
401 /******************************************************************
402 * macho_get_map_rva
404 DWORD_PTR macho_get_map_rva(const struct image_section_map* ism)
406 if (ism->sidx < 0 || ism->sidx >= ism->fmap->u.macho.num_sections ||
407 ism->fmap->u.macho.sect[ism->sidx].ignored)
408 return 0;
409 return ism->fmap->u.macho.sect[ism->sidx].section.addr - ism->fmap->u.macho.segs_start;
412 /******************************************************************
413 * macho_get_map_size
415 unsigned macho_get_map_size(const struct image_section_map* ism)
417 if (ism->sidx < 0 || ism->sidx >= ism->fmap->u.macho.num_sections ||
418 ism->fmap->u.macho.sect[ism->sidx].ignored)
419 return 0;
420 return ism->fmap->u.macho.sect[ism->sidx].section.size;
423 /******************************************************************
424 * macho_map_load_commands
426 * Maps the load commands from a Mach-O file into memory
428 static const struct load_command* macho_map_load_commands(struct macho_file_map* fmap)
430 if (fmap->load_commands == IMAGE_NO_MAP)
432 fmap->load_commands = (const struct load_command*) macho_map_range(
433 fmap, fmap->header_size, fmap->mach_header.sizeofcmds, NULL);
434 TRACE("Mapped load commands: %p\n", fmap->load_commands);
437 return fmap->load_commands;
440 /******************************************************************
441 * macho_unmap_load_commands
443 * Unmaps the load commands of a Mach-O file from memory
445 static void macho_unmap_load_commands(struct macho_file_map* fmap)
447 if (fmap->load_commands != IMAGE_NO_MAP)
449 TRACE("Unmapping load commands: %p\n", fmap->load_commands);
450 macho_unmap_range(NULL, (const void**)&fmap->load_commands, fmap,
451 fmap->header_size, fmap->mach_header.sizeofcmds);
455 /******************************************************************
456 * macho_next_load_command
458 * Advance to the next load command
460 static const struct load_command* macho_next_load_command(const struct load_command* lc)
462 return (const struct load_command*)((const char*)lc + lc->cmdsize);
465 /******************************************************************
466 * macho_enum_load_commands
468 * Enumerates the load commands for a Mach-O file, selecting by
469 * the command type, calling a callback for each. If the callback
470 * returns <0, that indicates an error. If it returns >0, that means
471 * it's not interested in getting any more load commands.
472 * If this function returns <0, that's an error produced by the
473 * callback. If >=0, that's the count of load commands successfully
474 * processed.
476 static int macho_enum_load_commands(struct image_file_map *ifm, unsigned cmd,
477 int (*cb)(struct image_file_map*, const struct load_command*, void*),
478 void* user)
480 struct macho_file_map* fmap = &ifm->u.macho;
481 const struct load_command* lc;
482 int i;
483 int count = 0;
485 TRACE("(%p/%d, %u, %p, %p)\n", fmap, fmap->fd, cmd, cb, user);
487 if ((lc = macho_map_load_commands(fmap)) == IMAGE_NO_MAP) return -1;
489 TRACE("%d total commands\n", fmap->mach_header.ncmds);
491 for (i = 0; i < fmap->mach_header.ncmds; i++, lc = macho_next_load_command(lc))
493 int result;
495 if (cmd && cmd != lc->cmd) continue;
496 count++;
498 result = cb(ifm, lc, user);
499 TRACE("load_command[%d] (%p), cmd %u; callback => %d\n", i, lc, lc->cmd, result);
500 if (result) return (result < 0) ? result : count;
503 return count;
506 /******************************************************************
507 * macho_count_sections
509 * Callback for macho_enum_load_commands. Counts the number of
510 * significant sections in a Mach-O file. All commands are
511 * expected to be of LC_SEGMENT[_64] type.
513 static int macho_count_sections(struct image_file_map* ifm, const struct load_command* lc, void* user)
515 char segname[16];
516 uint32_t nsects;
518 if (ifm->addr_size == 32)
520 const struct segment_command *sc = (const struct segment_command *)lc;
521 memcpy(segname, sc->segname, sizeof(segname));
522 nsects = sc->nsects;
524 else
526 const struct segment_command_64 *sc = (const struct segment_command_64 *)lc;
527 memcpy(segname, sc->segname, sizeof(segname));
528 nsects = sc->nsects;
531 TRACE("(%p/%d, %p, %p) segment %s\n", ifm, ifm->u.macho.fd, lc, user,
532 debugstr_an(segname, sizeof(segname)));
534 ifm->u.macho.num_sections += nsects;
535 return 0;
538 /******************************************************************
539 * macho_load_section_info
541 * Callback for macho_enum_load_commands. Accumulates the address
542 * range covered by the segments of a Mach-O file and builds the
543 * section map. All commands are expected to be of LC_SEGMENT[_64] type.
545 static int macho_load_section_info(struct image_file_map* ifm, const struct load_command* lc, void* user)
547 struct macho_file_map* fmap = &ifm->u.macho;
548 struct section_info* info = user;
549 BOOL ignore;
550 int i;
551 unsigned long tmp, page_mask = sysconf( _SC_PAGESIZE ) - 1;
552 uint64_t vmaddr, vmsize;
553 char segname[16];
554 uint32_t nsects;
555 const void *sections;
557 if (ifm->addr_size == 32)
559 const struct segment_command *sc = (const struct segment_command *)lc;
560 vmaddr = sc->vmaddr;
561 vmsize = sc->vmsize;
562 memcpy(segname, sc->segname, sizeof(segname));
563 nsects = sc->nsects;
564 sections = (const void *)(sc + 1);
566 else
568 const struct segment_command_64 *sc = (const struct segment_command_64 *)lc;
569 vmaddr = sc->vmaddr;
570 vmsize = sc->vmsize;
571 memcpy(segname, sc->segname, sizeof(segname));
572 nsects = sc->nsects;
573 sections = (const void *)(sc + 1);
576 TRACE("(%p/%d, %p, %p) before: 0x%08lx - 0x%08lx\n", fmap, fmap->fd, lc, user,
577 (unsigned long)fmap->segs_start, (unsigned long)fmap->segs_size);
578 TRACE("Segment command vm: 0x%08lx - 0x%08lx\n", (unsigned long)vmaddr,
579 (unsigned long)(vmaddr + vmsize));
581 /* Images in the dyld shared cache have their segments mapped non-contiguously.
582 We don't know how to properly locate any of the segments other than __TEXT,
583 so ignore them. */
584 ignore = (info->split_segs && strcmp(segname, SEG_TEXT));
586 if (!strncmp(segname, "WINE_", 5))
587 TRACE("Ignoring special Wine segment %s\n", debugstr_an(segname, sizeof(segname)));
588 else if (!strncmp(segname, "__PAGEZERO", 10))
589 TRACE("Ignoring __PAGEZERO segment\n");
590 else if (ignore)
591 TRACE("Ignoring %s segment because image has split segments\n", segname);
592 else
594 /* If this segment starts before previously-known earliest, record new earliest. */
595 if (vmaddr < fmap->segs_start)
596 fmap->segs_start = vmaddr;
598 /* If this segment extends beyond previously-known furthest, record new furthest. */
599 tmp = (vmaddr + vmsize + page_mask) & ~page_mask;
600 if (fmap->segs_size < tmp) fmap->segs_size = tmp;
602 TRACE("after: 0x%08lx - 0x%08lx\n", (unsigned long)fmap->segs_start, (unsigned long)fmap->segs_size);
605 for (i = 0; i < nsects; i++)
607 if (ifm->addr_size == 32)
609 const struct section *section = &((const struct section *)sections)[i];
610 memcpy(fmap->sect[info->section_index].section.sectname, section->sectname, sizeof(section->sectname));
611 memcpy(fmap->sect[info->section_index].section.segname, section->segname, sizeof(section->segname));
612 fmap->sect[info->section_index].section.addr = section->addr;
613 fmap->sect[info->section_index].section.size = section->size;
614 fmap->sect[info->section_index].section.offset = section->offset;
615 fmap->sect[info->section_index].section.align = section->align;
616 fmap->sect[info->section_index].section.reloff = section->reloff;
617 fmap->sect[info->section_index].section.nreloc = section->nreloc;
618 fmap->sect[info->section_index].section.flags = section->flags;
620 else
621 fmap->sect[info->section_index].section = ((const struct section_64 *)sections)[i];
623 fmap->sect[info->section_index].mapped = IMAGE_NO_MAP;
624 fmap->sect[info->section_index].ignored = ignore;
625 info->section_index++;
628 return 0;
631 /******************************************************************
632 * find_uuid
634 * Callback for macho_enum_load_commands. Records the UUID load
635 * command of a Mach-O file.
637 static int find_uuid(struct image_file_map* ifm, const struct load_command* lc, void* user)
639 ifm->u.macho.uuid = (const struct uuid_command*)lc;
640 return 1;
643 /******************************************************************
644 * reset_file_map
646 static inline void reset_file_map(struct image_file_map* ifm)
648 struct macho_file_map* fmap = &ifm->u.macho;
650 fmap->fd = -1;
651 fmap->dsym = NULL;
652 fmap->load_commands = IMAGE_NO_MAP;
653 fmap->uuid = NULL;
654 fmap->num_sections = 0;
655 fmap->sect = NULL;
658 /******************************************************************
659 * macho_map_file
661 * Maps a Mach-O file into memory (and checks it's a real Mach-O file)
663 static BOOL macho_map_file(struct process *pcs, const WCHAR *filenameW,
664 BOOL split_segs, struct image_file_map* ifm)
666 struct macho_file_map* fmap = &ifm->u.macho;
667 struct fat_header fat_header;
668 struct stat statbuf;
669 int i;
670 char* filename;
671 unsigned len;
672 struct section_info info;
673 BOOL ret = FALSE;
674 cpu_type_t target_cpu = (pcs->is_64bit) ? CPU_TYPE_X86_64 : CPU_TYPE_X86;
675 uint32_t target_magic = (pcs->is_64bit) ? MH_MAGIC_64 : MH_MAGIC;
676 uint32_t target_cmd = (pcs->is_64bit) ? LC_SEGMENT_64 : LC_SEGMENT;
678 TRACE("(%s, %p)\n", debugstr_w(filenameW), fmap);
680 reset_file_map(ifm);
682 ifm->modtype = DMT_MACHO;
683 ifm->addr_size = (pcs->is_64bit) ? 64 : 32;
684 fmap->header_size = (pcs->is_64bit) ? sizeof(struct mach_header_64) : sizeof(struct mach_header);
686 len = WideCharToMultiByte(CP_UNIXCP, 0, filenameW, -1, NULL, 0, NULL, NULL);
687 if (!(filename = HeapAlloc(GetProcessHeap(), 0, len)))
689 WARN("failed to allocate filename buffer\n");
690 return FALSE;
692 WideCharToMultiByte(CP_UNIXCP, 0, filenameW, -1, filename, len, NULL, NULL);
694 /* check that the file exists */
695 if (stat(filename, &statbuf) == -1 || S_ISDIR(statbuf.st_mode))
697 TRACE("stat() failed or %s is directory: %s\n", debugstr_a(filename), strerror(errno));
698 goto done;
701 /* Now open the file, so that we can mmap() it. */
702 if ((fmap->fd = open(filename, O_RDONLY)) == -1)
704 TRACE("failed to open file %s: %d\n", debugstr_a(filename), errno);
705 goto done;
708 if (read(fmap->fd, &fat_header, sizeof(fat_header)) != sizeof(fat_header))
710 TRACE("failed to read fat header: %d\n", errno);
711 goto done;
713 TRACE("... got possible fat header\n");
715 /* Fat header is always in big-endian order. */
716 if (swap_ulong_be_to_host(fat_header.magic) == FAT_MAGIC)
718 int narch = swap_ulong_be_to_host(fat_header.nfat_arch);
719 for (i = 0; i < narch; i++)
721 struct fat_arch fat_arch;
722 if (read(fmap->fd, &fat_arch, sizeof(fat_arch)) != sizeof(fat_arch))
723 goto done;
724 if (swap_ulong_be_to_host(fat_arch.cputype) == target_cpu)
726 fmap->arch_offset = swap_ulong_be_to_host(fat_arch.offset);
727 break;
730 if (i >= narch) goto done;
731 TRACE("... found target arch (%d)\n", target_cpu);
733 else
735 fmap->arch_offset = 0;
736 TRACE("... not a fat header\n");
739 /* Individual architecture (standalone or within a fat file) is in its native byte order. */
740 lseek(fmap->fd, fmap->arch_offset, SEEK_SET);
741 if (read(fmap->fd, &fmap->mach_header, sizeof(fmap->mach_header)) != sizeof(fmap->mach_header))
742 goto done;
743 TRACE("... got possible Mach header\n");
744 /* and check for a Mach-O header */
745 if (fmap->mach_header.magic != target_magic ||
746 fmap->mach_header.cputype != target_cpu) goto done;
747 /* Make sure the file type is one of the ones we expect. */
748 switch (fmap->mach_header.filetype)
750 case MH_EXECUTE:
751 case MH_DYLIB:
752 case MH_DYLINKER:
753 case MH_BUNDLE:
754 case MH_DSYM:
755 break;
756 default:
757 goto done;
759 TRACE("... verified Mach header\n");
761 fmap->num_sections = 0;
762 if (macho_enum_load_commands(ifm, target_cmd, macho_count_sections, NULL) < 0)
763 goto done;
764 TRACE("%d sections\n", fmap->num_sections);
766 fmap->sect = HeapAlloc(GetProcessHeap(), 0, fmap->num_sections * sizeof(fmap->sect[0]));
767 if (!fmap->sect)
768 goto done;
770 fmap->segs_size = 0;
771 fmap->segs_start = ~0L;
773 info.split_segs = split_segs;
774 info.section_index = 0;
775 if (macho_enum_load_commands(ifm, target_cmd, macho_load_section_info, &info) < 0)
777 fmap->num_sections = 0;
778 goto done;
781 fmap->segs_size -= fmap->segs_start;
782 TRACE("segs_start: 0x%08lx, segs_size: 0x%08lx\n", (unsigned long)fmap->segs_start,
783 (unsigned long)fmap->segs_size);
785 if (macho_enum_load_commands(ifm, LC_UUID, find_uuid, NULL) < 0)
786 goto done;
787 if (fmap->uuid)
789 char uuid_string[UUID_STRING_LEN];
790 TRACE("UUID %s\n", format_uuid(fmap->uuid->uuid, uuid_string));
792 else
793 TRACE("no UUID found\n");
795 ret = TRUE;
796 done:
797 if (!ret)
798 macho_unmap_file(ifm);
799 HeapFree(GetProcessHeap(), 0, filename);
800 return ret;
803 /******************************************************************
804 * macho_unmap_file
806 * Unmaps a Mach-O file from memory (previously mapped with macho_map_file)
808 static void macho_unmap_file(struct image_file_map* ifm)
810 struct image_file_map* cursor;
812 TRACE("(%p/%d)\n", ifm, ifm->u.macho.fd);
814 cursor = ifm;
815 while (cursor)
817 struct image_file_map* next;
819 if (ifm->u.macho.fd != -1)
821 struct image_section_map ism;
823 ism.fmap = ifm;
824 for (ism.sidx = 0; ism.sidx < ifm->u.macho.num_sections; ism.sidx++)
825 macho_unmap_section(&ism);
827 HeapFree(GetProcessHeap(), 0, ifm->u.macho.sect);
828 macho_unmap_load_commands(&ifm->u.macho);
829 close(ifm->u.macho.fd);
830 ifm->u.macho.fd = -1;
833 next = cursor->u.macho.dsym;
834 if (cursor != ifm)
835 HeapFree(GetProcessHeap(), 0, cursor);
836 cursor = next;
840 /******************************************************************
841 * macho_sect_is_code
843 * Checks if a section, identified by sectidx which is a 1-based
844 * index into the sections of all segments, in order of load
845 * commands, contains code.
847 static BOOL macho_sect_is_code(struct macho_file_map* fmap, unsigned char sectidx)
849 BOOL ret;
851 TRACE("(%p/%d, %u)\n", fmap, fmap->fd, sectidx);
853 if (!sectidx) return FALSE;
855 sectidx--; /* convert from 1-based to 0-based */
856 if (sectidx >= fmap->num_sections || fmap->sect[sectidx].ignored) return FALSE;
858 ret = (!(fmap->sect[sectidx].section.flags & SECTION_TYPE) &&
859 (fmap->sect[sectidx].section.flags & (S_ATTR_PURE_INSTRUCTIONS|S_ATTR_SOME_INSTRUCTIONS)));
860 TRACE("-> %d\n", ret);
861 return ret;
864 struct symtab_elt
866 struct hash_table_elt ht_elt;
867 struct symt_compiland* compiland;
868 unsigned long addr;
869 unsigned char is_code:1,
870 is_public:1,
871 is_global:1,
872 used:1;
875 struct macho_debug_info
877 struct macho_file_map* fmap;
878 struct module* module;
879 struct pool pool;
880 struct hash_table ht_symtab;
883 /******************************************************************
884 * macho_stabs_def_cb
886 * Callback for stabs_parse. Collect symbol definitions.
888 static void macho_stabs_def_cb(struct module* module, unsigned long load_offset,
889 const char* name, unsigned long offset,
890 BOOL is_public, BOOL is_global, unsigned char sectidx,
891 struct symt_compiland* compiland, void* user)
893 struct macho_debug_info* mdi = user;
894 struct symtab_elt* ste;
896 TRACE("(%p, 0x%08lx, %s, 0x%08lx, %d, %d, %u, %p, %p/%p/%d)\n", module, load_offset,
897 debugstr_a(name), offset, is_public, is_global, sectidx,
898 compiland, mdi, mdi->fmap, mdi->fmap->fd);
900 /* Defer the creation of new non-debugging symbols until after we've
901 * finished parsing the stabs. */
902 ste = pool_alloc(&mdi->pool, sizeof(*ste));
903 ste->ht_elt.name = pool_strdup(&mdi->pool, name);
904 ste->compiland = compiland;
905 ste->addr = load_offset + offset;
906 ste->is_code = !!macho_sect_is_code(mdi->fmap, sectidx);
907 ste->is_public = !!is_public;
908 ste->is_global = !!is_global;
909 ste->used = 0;
910 hash_table_add(&mdi->ht_symtab, &ste->ht_elt);
913 /******************************************************************
914 * macho_parse_symtab
916 * Callback for macho_enum_load_commands. Processes the LC_SYMTAB
917 * load commands from the Mach-O file.
919 static int macho_parse_symtab(struct image_file_map* ifm,
920 const struct load_command* lc, void* user)
922 struct macho_file_map* fmap = &ifm->u.macho;
923 const struct symtab_command* sc = (const struct symtab_command*)lc;
924 struct macho_debug_info* mdi = user;
925 const char* stabstr;
926 int ret = 0;
927 size_t stabsize = (ifm->addr_size == 32) ? sizeof(struct nlist) : sizeof(struct nlist_64);
928 const char *stab;
930 TRACE("(%p/%d, %p, %p) %u syms at 0x%08x, strings 0x%08x - 0x%08x\n", fmap, fmap->fd, lc,
931 user, sc->nsyms, sc->symoff, sc->stroff, sc->stroff + sc->strsize);
933 if (!macho_map_ranges(fmap, sc->symoff, sc->nsyms * stabsize,
934 sc->stroff, sc->strsize, (const void**)&stab, (const void**)&stabstr))
935 return 0;
937 if (!stabs_parse(mdi->module,
938 mdi->module->format_info[DFI_MACHO]->u.macho_info->load_addr - fmap->segs_start,
939 stab, sc->nsyms * stabsize,
940 stabstr, sc->strsize, macho_stabs_def_cb, mdi))
941 ret = -1;
943 macho_unmap_ranges(fmap, sc->symoff, sc->nsyms * stabsize,
944 sc->stroff, sc->strsize, (const void**)&stab, (const void**)&stabstr);
946 return ret;
949 /******************************************************************
950 * macho_finish_stabs
952 * Integrate the non-debugging symbols we've gathered into the
953 * symbols that were generated during stabs parsing.
955 static void macho_finish_stabs(struct module* module, struct hash_table* ht_symtab)
957 struct hash_table_iter hti_ours;
958 struct symtab_elt* ste;
959 BOOL adjusted = FALSE;
961 TRACE("(%p, %p)\n", module, ht_symtab);
963 /* For each of our non-debugging symbols, see if it can provide some
964 * missing details to one of the module's known symbols. */
965 hash_table_iter_init(ht_symtab, &hti_ours, NULL);
966 while ((ste = hash_table_iter_up(&hti_ours)))
968 struct hash_table_iter hti_modules;
969 void* ptr;
970 struct symt_ht* sym;
971 struct symt_function* func;
972 struct symt_data* data;
974 hash_table_iter_init(&module->ht_symbols, &hti_modules, ste->ht_elt.name);
975 while ((ptr = hash_table_iter_up(&hti_modules)))
977 sym = CONTAINING_RECORD(ptr, struct symt_ht, hash_elt);
979 if (strcmp(sym->hash_elt.name, ste->ht_elt.name))
980 continue;
982 switch (sym->symt.tag)
984 case SymTagFunction:
985 func = (struct symt_function*)sym;
986 if (func->address == module->format_info[DFI_MACHO]->u.macho_info->load_addr)
988 TRACE("Adjusting function %p/%s!%s from 0x%08lx to 0x%08lx\n", func,
989 debugstr_w(module->module.ModuleName), sym->hash_elt.name,
990 func->address, ste->addr);
991 func->address = ste->addr;
992 adjusted = TRUE;
994 if (func->address == ste->addr)
995 ste->used = 1;
996 break;
997 case SymTagData:
998 data = (struct symt_data*)sym;
999 switch (data->kind)
1001 case DataIsGlobal:
1002 case DataIsFileStatic:
1003 if (data->u.var.offset == module->format_info[DFI_MACHO]->u.macho_info->load_addr)
1005 TRACE("Adjusting data symbol %p/%s!%s from 0x%08lx to 0x%08lx\n",
1006 data, debugstr_w(module->module.ModuleName), sym->hash_elt.name,
1007 data->u.var.offset, ste->addr);
1008 data->u.var.offset = ste->addr;
1009 adjusted = TRUE;
1011 if (data->u.var.offset == ste->addr)
1013 enum DataKind new_kind;
1015 new_kind = ste->is_global ? DataIsGlobal : DataIsFileStatic;
1016 if (data->kind != new_kind)
1018 WARN("Changing kind for %p/%s!%s from %d to %d\n", sym,
1019 debugstr_w(module->module.ModuleName), sym->hash_elt.name,
1020 (int)data->kind, (int)new_kind);
1021 data->kind = new_kind;
1022 adjusted = TRUE;
1024 ste->used = 1;
1026 break;
1027 default:;
1029 break;
1030 default:
1031 TRACE("Ignoring tag %u\n", sym->symt.tag);
1032 break;
1037 if (adjusted)
1039 /* since we may have changed some addresses, mark the module to be resorted */
1040 module->sortlist_valid = FALSE;
1043 /* Mark any of our non-debugging symbols which fall on an already-used
1044 * address as "used". This allows us to skip them in the next loop,
1045 * below. We do this in separate loops because symt_new_* marks the
1046 * list as needing sorting and symt_find_nearest sorts if needed,
1047 * causing thrashing. */
1048 if (!(dbghelp_options & SYMOPT_PUBLICS_ONLY))
1050 hash_table_iter_init(ht_symtab, &hti_ours, NULL);
1051 while ((ste = hash_table_iter_up(&hti_ours)))
1053 struct symt_ht* sym;
1054 ULONG64 addr;
1056 if (ste->used) continue;
1058 sym = symt_find_nearest(module, ste->addr);
1059 if (sym)
1060 symt_get_address(&sym->symt, &addr);
1061 if (sym && ste->addr == addr)
1063 ULONG64 size = 0;
1064 DWORD kind = -1;
1066 ste->used = 1;
1068 /* If neither symbol has a correct size (ours never does), we
1069 * consider them both to be markers. No warning is needed in
1070 * that case.
1071 * Also, we check that we don't have two symbols, one local, the other
1072 * global, which is legal.
1074 symt_get_info(module, &sym->symt, TI_GET_LENGTH, &size);
1075 symt_get_info(module, &sym->symt, TI_GET_DATAKIND, &kind);
1076 if (size && kind == (ste->is_global ? DataIsGlobal : DataIsFileStatic))
1077 FIXME("Duplicate in %s: %s<%08lx> %s<%s-%s>\n",
1078 debugstr_w(module->module.ModuleName),
1079 ste->ht_elt.name, ste->addr,
1080 sym->hash_elt.name,
1081 wine_dbgstr_longlong(addr), wine_dbgstr_longlong(size));
1086 /* For any of our remaining non-debugging symbols which have no match
1087 * among the module's known symbols, add them as new symbols. */
1088 hash_table_iter_init(ht_symtab, &hti_ours, NULL);
1089 while ((ste = hash_table_iter_up(&hti_ours)))
1091 if (!(dbghelp_options & SYMOPT_PUBLICS_ONLY) && !ste->used)
1093 if (ste->is_code)
1095 symt_new_function(module, ste->compiland, ste->ht_elt.name,
1096 ste->addr, 0, NULL);
1098 else
1100 struct location loc;
1102 loc.kind = loc_absolute;
1103 loc.reg = 0;
1104 loc.offset = ste->addr;
1105 symt_new_global_variable(module, ste->compiland, ste->ht_elt.name,
1106 !ste->is_global, loc, 0, NULL);
1109 ste->used = 1;
1112 if (ste->is_public && !(dbghelp_options & SYMOPT_NO_PUBLICS))
1114 symt_new_public(module, ste->compiland, ste->ht_elt.name, ste->is_code, ste->addr, 0);
1119 /******************************************************************
1120 * try_dsym
1122 * Try to load a debug symbol file from the given path and check
1123 * if its UUID matches the UUID of an already-mapped file. If so,
1124 * stash the file map in the "dsym" field of the file and return
1125 * TRUE. If it can't be mapped or its UUID doesn't match, return
1126 * FALSE.
1128 static BOOL try_dsym(struct process *pcs, const WCHAR* path, struct macho_file_map* fmap)
1130 struct image_file_map dsym_ifm;
1132 if (macho_map_file(pcs, path, FALSE, &dsym_ifm))
1134 char uuid_string[UUID_STRING_LEN];
1136 if (dsym_ifm.u.macho.uuid && !memcmp(dsym_ifm.u.macho.uuid->uuid, fmap->uuid->uuid, sizeof(fmap->uuid->uuid)))
1138 TRACE("found matching debug symbol file at %s\n", debugstr_w(path));
1139 fmap->dsym = HeapAlloc(GetProcessHeap(), 0, sizeof(dsym_ifm));
1140 *fmap->dsym = dsym_ifm;
1141 return TRUE;
1144 TRACE("candidate debug symbol file at %s has wrong UUID %s; ignoring\n", debugstr_w(path),
1145 format_uuid(dsym_ifm.u.macho.uuid->uuid, uuid_string));
1147 macho_unmap_file(&dsym_ifm);
1149 else
1150 TRACE("couldn't map file at %s\n", debugstr_w(path));
1152 return FALSE;
1155 /******************************************************************
1156 * find_and_map_dsym
1158 * Search for a debugging symbols file associated with a module and
1159 * map it. First look for a .dSYM bundle next to the module file
1160 * (e.g. <path>.dSYM/Contents/Resources/DWARF/<basename of path>)
1161 * as produced by dsymutil. Next, look for a .dwarf file next to
1162 * the module file (e.g. <path>.dwarf) as produced by
1163 * "dsymutil --flat". Finally, use Spotlight to search for a
1164 * .dSYM bundle with the same UUID as the module file.
1166 static void find_and_map_dsym(struct process *pcs, struct module* module)
1168 static const WCHAR dot_dsym[] = {'.','d','S','Y','M',0};
1169 static const WCHAR dsym_subpath[] = {'/','C','o','n','t','e','n','t','s','/','R','e','s','o','u','r','c','e','s','/','D','W','A','R','F','/',0};
1170 static const WCHAR dot_dwarf[] = {'.','d','w','a','r','f',0};
1171 struct macho_file_map* fmap = &module->format_info[DFI_MACHO]->u.macho_info->file_map.u.macho;
1172 const WCHAR* p;
1173 size_t len;
1174 WCHAR* path = NULL;
1175 char uuid_string[UUID_STRING_LEN];
1176 CFStringRef uuid_cfstring;
1177 CFStringRef query_string;
1178 MDQueryRef query = NULL;
1180 /* Without a UUID, we can't verify that any debug info file we find corresponds
1181 to this file. Better to have no debug info than incorrect debug info. */
1182 if (!fmap->uuid)
1183 return;
1185 if ((p = strrchrW(module->module.LoadedImageName, '/')))
1186 p++;
1187 else
1188 p = module->module.LoadedImageName;
1189 len = strlenW(module->module.LoadedImageName) + strlenW(dot_dsym) + strlenW(dsym_subpath) + strlenW(p) + 1;
1190 path = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1191 if (!path)
1192 return;
1193 strcpyW(path, module->module.LoadedImageName);
1194 strcatW(path, dot_dsym);
1195 strcatW(path, dsym_subpath);
1196 strcatW(path, p);
1198 if (try_dsym(pcs, path, fmap))
1199 goto found;
1201 strcpyW(path + strlenW(module->module.LoadedImageName), dot_dwarf);
1203 if (try_dsym(pcs, path, fmap))
1204 goto found;
1206 format_uuid(fmap->uuid->uuid, uuid_string);
1207 uuid_cfstring = CFStringCreateWithCString(NULL, uuid_string, kCFStringEncodingASCII);
1208 query_string = CFStringCreateWithFormat(NULL, NULL, CFSTR("com_apple_xcode_dsym_uuids == \"%@\""), uuid_cfstring);
1209 CFRelease(uuid_cfstring);
1210 query = MDQueryCreate(NULL, query_string, NULL, NULL);
1211 CFRelease(query_string);
1212 MDQuerySetMaxCount(query, 1);
1213 if (MDQueryExecute(query, kMDQuerySynchronous) && MDQueryGetResultCount(query) >= 1)
1215 MDItemRef item = (MDItemRef)MDQueryGetResultAtIndex(query, 0);
1216 CFStringRef item_path = MDItemCopyAttribute(item, kMDItemPath);
1217 if (item_path)
1219 CFIndex item_path_len = CFStringGetLength(item_path);
1220 if (item_path_len + strlenW(dsym_subpath) + strlenW(p) >= len)
1222 HeapFree(GetProcessHeap(), 0, path);
1223 len = item_path_len + strlenW(dsym_subpath) + strlenW(p) + 1;
1224 path = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1226 CFStringGetCharacters(item_path, CFRangeMake(0, item_path_len), (UniChar*)path);
1227 strcpyW(path + item_path_len, dsym_subpath);
1228 strcatW(path, p);
1229 CFRelease(item_path);
1231 if (try_dsym(pcs, path, fmap))
1232 goto found;
1236 found:
1237 HeapFree(GetProcessHeap(), 0, path);
1238 if (query) CFRelease(query);
1241 /******************************************************************
1242 * image_uses_split_segs
1244 * Determine if the Mach-O image loaded at a particular address in
1245 * the given process is in the dyld shared cache and therefore has
1246 * its segments mapped non-contiguously.
1248 * The image header has to be loaded from the process's memory
1249 * because the relevant flag is only set in memory, not in the file.
1251 static BOOL image_uses_split_segs(HANDLE process, unsigned long load_addr)
1253 BOOL split_segs = FALSE;
1255 if (process && load_addr)
1257 struct process *pcs = process_find_by_handle(process);
1258 cpu_type_t target_cpu = (pcs->is_64bit) ? CPU_TYPE_X86_64 : CPU_TYPE_X86;
1259 uint32_t target_magic = (pcs->is_64bit) ? MH_MAGIC_64 : MH_MAGIC;
1260 struct mach_header header;
1262 if (ReadProcessMemory(process, (void*)load_addr, &header, sizeof(header), NULL) &&
1263 header.magic == target_magic && header.cputype == target_cpu &&
1264 header.flags & MACHO_DYLD_IN_SHARED_CACHE)
1266 split_segs = TRUE;
1270 return split_segs;
1273 /******************************************************************
1274 * macho_load_debug_info
1276 * Loads Mach-O debugging information from the module image file.
1278 BOOL macho_load_debug_info(struct process *pcs, struct module* module)
1280 BOOL ret = FALSE;
1281 struct macho_debug_info mdi;
1282 int result;
1283 struct image_file_map *ifm;
1284 struct macho_file_map *fmap;
1286 if (module->type != DMT_MACHO || !module->format_info[DFI_MACHO]->u.macho_info)
1288 ERR("Bad Mach-O module '%s'\n", debugstr_w(module->module.LoadedImageName));
1289 return FALSE;
1292 ifm = &module->format_info[DFI_MACHO]->u.macho_info->file_map;
1293 fmap = &ifm->u.macho;
1295 TRACE("(%p, %p/%d)\n", module, fmap, fmap->fd);
1297 module->module.SymType = SymExport;
1299 if (!(dbghelp_options & SYMOPT_PUBLICS_ONLY))
1301 find_and_map_dsym(pcs, module);
1303 if (dwarf2_parse(module, module->reloc_delta, NULL /* FIXME: some thunks to deal with ? */,
1304 &module->format_info[DFI_MACHO]->u.macho_info->file_map))
1305 ret = TRUE;
1308 mdi.fmap = fmap;
1309 mdi.module = module;
1310 pool_init(&mdi.pool, 65536);
1311 hash_table_init(&mdi.pool, &mdi.ht_symtab, 256);
1312 result = macho_enum_load_commands(ifm, LC_SYMTAB, macho_parse_symtab, &mdi);
1313 if (result > 0)
1314 ret = TRUE;
1315 else if (result < 0)
1316 WARN("Couldn't correctly read stabs\n");
1318 if (!(dbghelp_options & SYMOPT_PUBLICS_ONLY) && fmap->dsym)
1320 mdi.fmap = &fmap->dsym->u.macho;
1321 result = macho_enum_load_commands(fmap->dsym, LC_SYMTAB, macho_parse_symtab, &mdi);
1322 if (result > 0)
1323 ret = TRUE;
1324 else if (result < 0)
1325 WARN("Couldn't correctly read stabs\n");
1328 macho_finish_stabs(module, &mdi.ht_symtab);
1330 pool_destroy(&mdi.pool);
1331 return ret;
1334 /******************************************************************
1335 * macho_fetch_file_info
1337 * Gathers some more information for a Mach-O module from a given file
1339 BOOL macho_fetch_file_info(HANDLE process, const WCHAR* name, unsigned long load_addr, DWORD_PTR* base,
1340 DWORD* size, DWORD* checksum)
1342 struct image_file_map fmap;
1343 struct process *pcs;
1344 BOOL split_segs;
1346 TRACE("(%s, %p, %p, %p)\n", debugstr_w(name), base, size, checksum);
1348 pcs = process_find_by_handle(process);
1349 if (!pcs) return FALSE;
1351 split_segs = image_uses_split_segs(process, load_addr);
1352 if (!macho_map_file(pcs, name, split_segs, &fmap)) return FALSE;
1353 if (base) *base = fmap.u.macho.segs_start;
1354 *size = fmap.u.macho.segs_size;
1355 *checksum = calc_crc32(fmap.u.macho.fd);
1356 macho_unmap_file(&fmap);
1357 return TRUE;
1360 /******************************************************************
1361 * macho_module_remove
1363 static void macho_module_remove(struct process* pcs, struct module_format* modfmt)
1365 macho_unmap_file(&modfmt->u.macho_info->file_map);
1366 HeapFree(GetProcessHeap(), 0, modfmt);
1370 /******************************************************************
1371 * get_dyld_image_info_address
1373 static ULONG_PTR get_dyld_image_info_address(struct process* pcs)
1375 NTSTATUS status;
1376 PROCESS_BASIC_INFORMATION pbi;
1377 ULONG_PTR dyld_image_info_address = 0;
1378 BOOL ret;
1380 /* Get address of PEB */
1381 status = NtQueryInformationProcess(pcs->handle, ProcessBasicInformation, &pbi, sizeof(pbi), NULL);
1382 if (status == STATUS_SUCCESS)
1384 /* Read dyld image info address from PEB */
1385 if (pcs->is_64bit)
1386 ret = ReadProcessMemory(pcs->handle, &pbi.PebBaseAddress->Reserved[0],
1387 &dyld_image_info_address, sizeof(dyld_image_info_address), NULL);
1388 else
1390 PEB32 *peb32 = (PEB32 *)pbi.PebBaseAddress;
1391 ULONG addr32;
1392 ret = ReadProcessMemory(pcs->handle, &peb32->Reserved[0], &addr32,
1393 sizeof(addr32), NULL);
1394 dyld_image_info_address = addr32;
1397 if (ret)
1398 TRACE("got dyld_image_info_address %#lx from PEB %p\n",
1399 dyld_image_info_address, pbi.PebBaseAddress);
1402 #ifndef __LP64__ /* No reading the symtab with nlist(3) in LP64 */
1403 if (!dyld_image_info_address)
1405 static void* dyld_all_image_infos_addr;
1407 /* Our next best guess is that dyld was loaded at its base address
1408 and we can find the dyld image infos address by looking up its symbol. */
1409 if (!dyld_all_image_infos_addr)
1411 struct nlist nl[2];
1412 memset(nl, 0, sizeof(nl));
1413 nl[0].n_un.n_name = (char*)"_dyld_all_image_infos";
1414 if (!nlist("/usr/lib/dyld", nl))
1415 dyld_all_image_infos_addr = (void*)nl[0].n_value;
1418 if (dyld_all_image_infos_addr)
1420 TRACE("got dyld_image_info_address %p from /usr/lib/dyld symbol table\n",
1421 dyld_all_image_infos_addr);
1422 dyld_image_info_address = (ULONG_PTR)dyld_all_image_infos_addr;
1425 #endif
1427 return dyld_image_info_address;
1430 /******************************************************************
1431 * macho_load_file
1433 * Loads the information for Mach-O module stored in 'filename'.
1434 * The module has been loaded at 'load_addr' address.
1435 * returns
1436 * FALSE if the file cannot be found/opened or if the file doesn't
1437 * contain symbolic info (or this info cannot be read or parsed)
1438 * TRUE on success
1440 static BOOL macho_load_file(struct process* pcs, const WCHAR* filename,
1441 unsigned long load_addr, struct macho_info* macho_info)
1443 BOOL ret = TRUE;
1444 BOOL split_segs;
1445 struct image_file_map fmap;
1447 TRACE("(%p/%p, %s, 0x%08lx, %p/0x%08x)\n", pcs, pcs->handle, debugstr_w(filename),
1448 load_addr, macho_info, macho_info->flags);
1450 split_segs = image_uses_split_segs(pcs->handle, load_addr);
1451 if (!macho_map_file(pcs, filename, split_segs, &fmap)) return FALSE;
1453 /* Find the dynamic loader's table of images loaded into the process.
1455 if (macho_info->flags & MACHO_INFO_DEBUG_HEADER)
1457 macho_info->dbg_hdr_addr = (unsigned long)get_dyld_image_info_address(pcs);
1458 ret = TRUE;
1461 if (macho_info->flags & MACHO_INFO_MODULE)
1463 struct macho_module_info *macho_module_info;
1464 struct module_format* modfmt =
1465 HeapAlloc(GetProcessHeap(), 0, sizeof(struct module_format) + sizeof(struct macho_module_info));
1466 if (!modfmt) goto leave;
1467 if (!load_addr)
1468 load_addr = fmap.u.macho.segs_start;
1469 macho_info->module = module_new(pcs, filename, DMT_MACHO, FALSE, load_addr,
1470 fmap.u.macho.segs_size, 0, calc_crc32(fmap.u.macho.fd));
1471 if (!macho_info->module)
1473 HeapFree(GetProcessHeap(), 0, modfmt);
1474 goto leave;
1476 macho_info->module->reloc_delta = macho_info->module->module.BaseOfImage - fmap.u.macho.segs_start;
1477 macho_module_info = (void*)(modfmt + 1);
1478 macho_info->module->format_info[DFI_MACHO] = modfmt;
1480 modfmt->module = macho_info->module;
1481 modfmt->remove = macho_module_remove;
1482 modfmt->loc_compute = NULL;
1483 modfmt->u.macho_info = macho_module_info;
1485 macho_module_info->load_addr = load_addr;
1487 macho_module_info->file_map = fmap;
1488 reset_file_map(&fmap);
1489 if (dbghelp_options & SYMOPT_DEFERRED_LOADS)
1490 macho_info->module->module.SymType = SymDeferred;
1491 else if (!macho_load_debug_info(pcs, macho_info->module))
1492 ret = FALSE;
1494 macho_info->module->format_info[DFI_MACHO]->u.macho_info->in_use = 1;
1495 macho_info->module->format_info[DFI_MACHO]->u.macho_info->is_loader = 0;
1496 TRACE("module = %p\n", macho_info->module);
1499 if (macho_info->flags & MACHO_INFO_NAME)
1501 WCHAR* ptr;
1502 ptr = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(filename) + 1) * sizeof(WCHAR));
1503 if (ptr)
1505 strcpyW(ptr, filename);
1506 macho_info->module_name = ptr;
1508 else ret = FALSE;
1509 TRACE("module_name = %p %s\n", macho_info->module_name, debugstr_w(macho_info->module_name));
1511 leave:
1512 macho_unmap_file(&fmap);
1514 TRACE(" => %d\n", ret);
1515 return ret;
1518 /******************************************************************
1519 * macho_load_file_from_path
1520 * Tries to load a Mach-O file from a set of paths (separated by ':')
1522 static BOOL macho_load_file_from_path(struct process* pcs,
1523 const WCHAR* filename,
1524 unsigned long load_addr,
1525 const char* path,
1526 struct macho_info* macho_info)
1528 BOOL ret = FALSE;
1529 WCHAR *s, *t, *fn;
1530 WCHAR* pathW = NULL;
1531 unsigned len;
1533 TRACE("(%p/%p, %s, 0x%08lx, %s, %p)\n", pcs, pcs->handle, debugstr_w(filename), load_addr,
1534 debugstr_a(path), macho_info);
1536 if (!path) return FALSE;
1538 len = MultiByteToWideChar(CP_UNIXCP, 0, path, -1, NULL, 0);
1539 pathW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1540 if (!pathW) return FALSE;
1541 MultiByteToWideChar(CP_UNIXCP, 0, path, -1, pathW, len);
1543 for (s = pathW; s && *s; s = (t) ? (t+1) : NULL)
1545 t = strchrW(s, ':');
1546 if (t) *t = '\0';
1547 fn = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(filename) + 1 + lstrlenW(s) + 1) * sizeof(WCHAR));
1548 if (!fn) break;
1549 strcpyW(fn, s);
1550 strcatW(fn, S_SlashW);
1551 strcatW(fn, filename);
1552 ret = macho_load_file(pcs, fn, load_addr, macho_info);
1553 HeapFree(GetProcessHeap(), 0, fn);
1554 if (ret) break;
1555 s = (t) ? (t+1) : NULL;
1558 TRACE(" => %d\n", ret);
1559 HeapFree(GetProcessHeap(), 0, pathW);
1560 return ret;
1563 /******************************************************************
1564 * macho_load_file_from_dll_path
1566 * Tries to load a Mach-O file from the dll path
1568 static BOOL macho_load_file_from_dll_path(struct process* pcs,
1569 const WCHAR* filename,
1570 unsigned long load_addr,
1571 struct macho_info* macho_info)
1573 BOOL ret = FALSE;
1574 unsigned int index = 0;
1575 const char *path;
1577 TRACE("(%p/%p, %s, 0x%08lx, %p)\n", pcs, pcs->handle, debugstr_w(filename), load_addr,
1578 macho_info);
1580 while (!ret && (path = wine_dll_enum_load_path( index++ )))
1582 WCHAR *name;
1583 unsigned len;
1585 len = MultiByteToWideChar(CP_UNIXCP, 0, path, -1, NULL, 0);
1587 name = HeapAlloc( GetProcessHeap(), 0,
1588 (len + lstrlenW(filename) + 2) * sizeof(WCHAR) );
1590 if (!name) break;
1591 MultiByteToWideChar(CP_UNIXCP, 0, path, -1, name, len);
1592 strcatW( name, S_SlashW );
1593 strcatW( name, filename );
1594 ret = macho_load_file(pcs, name, load_addr, macho_info);
1595 HeapFree( GetProcessHeap(), 0, name );
1597 TRACE(" => %d\n", ret);
1598 return ret;
1601 /******************************************************************
1602 * macho_search_and_load_file
1604 * Lookup a file in standard Mach-O locations, and if found, load it
1606 static BOOL macho_search_and_load_file(struct process* pcs, const WCHAR* filename,
1607 unsigned long load_addr,
1608 struct macho_info* macho_info)
1610 BOOL ret = FALSE;
1611 struct module* module;
1612 static const WCHAR S_libstdcPPW[] = {'l','i','b','s','t','d','c','+','+','\0'};
1613 const WCHAR* p;
1615 TRACE("(%p/%p, %s, 0x%08lx, %p)\n", pcs, pcs->handle, debugstr_w(filename), load_addr,
1616 macho_info);
1618 if (filename == NULL || *filename == '\0') return FALSE;
1619 if ((module = module_is_already_loaded(pcs, filename)))
1621 macho_info->module = module;
1622 module->format_info[DFI_MACHO]->u.macho_info->in_use = 1;
1623 return module->module.SymType;
1626 if (strstrW(filename, S_libstdcPPW)) return FALSE; /* We know we can't do it */
1628 /* If has no directories, try PATH first. */
1629 if (!strchrW(filename, '/'))
1631 ret = macho_load_file_from_path(pcs, filename, load_addr,
1632 getenv("PATH"), macho_info);
1634 /* Try DYLD_LIBRARY_PATH, with just the filename (no directories). */
1635 if (!ret)
1637 if ((p = strrchrW(filename, '/'))) p++;
1638 else p = filename;
1639 ret = macho_load_file_from_path(pcs, p, load_addr,
1640 getenv("DYLD_LIBRARY_PATH"), macho_info);
1642 /* Try the path as given. */
1643 if (!ret)
1644 ret = macho_load_file(pcs, filename, load_addr, macho_info);
1645 /* Try DYLD_FALLBACK_LIBRARY_PATH, with just the filename (no directories). */
1646 if (!ret)
1648 const char* fallback = getenv("DYLD_FALLBACK_LIBRARY_PATH");
1649 if (!fallback)
1650 fallback = "/usr/local/lib:/lib:/usr/lib";
1651 ret = macho_load_file_from_path(pcs, p, load_addr, fallback, macho_info);
1653 if (!ret && !strchrW(filename, '/'))
1654 ret = macho_load_file_from_dll_path(pcs, filename, load_addr, macho_info);
1656 return ret;
1659 /******************************************************************
1660 * macho_enum_modules_internal
1662 * Enumerate Mach-O modules from a running process
1664 static BOOL macho_enum_modules_internal(const struct process* pcs,
1665 const WCHAR* main_name,
1666 enum_modules_cb cb, void* user)
1668 union wine_all_image_infos image_infos;
1669 union wine_image_info* info_array = NULL;
1670 unsigned long len;
1671 int i;
1672 char bufstr[256];
1673 WCHAR bufstrW[MAX_PATH];
1674 BOOL ret = FALSE;
1676 TRACE("(%p/%p, %s, %p, %p)\n", pcs, pcs->handle, debugstr_w(main_name), cb,
1677 user);
1679 if (pcs->is_64bit)
1680 len = sizeof(image_infos.infos64);
1681 else
1682 len = sizeof(image_infos.infos32);
1683 if (!pcs->dbg_hdr_addr ||
1684 !ReadProcessMemory(pcs->handle, (void*)pcs->dbg_hdr_addr,
1685 &image_infos, len, NULL))
1686 goto done;
1687 if (!pcs->is_64bit)
1689 struct dyld_all_image_infos32 temp = image_infos.infos32;
1690 image_infos.infos64.infoArrayCount = temp.infoArrayCount;
1691 image_infos.infos64.infoArray = temp.infoArray;
1693 if (!image_infos.infos64.infoArray)
1694 goto done;
1695 TRACE("Process has %u image infos at %p\n", image_infos.infos64.infoArrayCount, (void*)image_infos.infos64.infoArray);
1697 if (pcs->is_64bit)
1698 len = sizeof(info_array->info64);
1699 else
1700 len = sizeof(info_array->info32);
1701 len *= image_infos.infos64.infoArrayCount;
1702 info_array = HeapAlloc(GetProcessHeap(), 0, len);
1703 if (!info_array ||
1704 !ReadProcessMemory(pcs->handle, (void*)image_infos.infos64.infoArray,
1705 info_array, len, NULL))
1706 goto done;
1707 TRACE("... read image infos\n");
1709 for (i = 0; i < image_infos.infos64.infoArrayCount; i++)
1711 struct dyld_image_info64 info;
1712 if (pcs->is_64bit)
1713 info = info_array[i].info64;
1714 else
1716 struct dyld_image_info32 *info32 = &info_array->info32 + i;
1717 info.imageLoadAddress = info32->imageLoadAddress;
1718 info.imageFilePath = info32->imageFilePath;
1720 if (info.imageFilePath &&
1721 ReadProcessMemory(pcs->handle, (void*)info.imageFilePath, bufstr, sizeof(bufstr), NULL))
1723 bufstr[sizeof(bufstr) - 1] = '\0';
1724 TRACE("[%d] image file %s\n", i, debugstr_a(bufstr));
1725 MultiByteToWideChar(CP_UNIXCP, 0, bufstr, -1, bufstrW, ARRAY_SIZE(bufstrW));
1726 if (main_name && !bufstrW[0]) strcpyW(bufstrW, main_name);
1727 if (!cb(bufstrW, info.imageLoadAddress, user)) break;
1731 ret = TRUE;
1732 done:
1733 HeapFree(GetProcessHeap(), 0, info_array);
1734 return ret;
1737 struct macho_sync
1739 struct process* pcs;
1740 struct macho_info macho_info;
1743 static BOOL macho_enum_sync_cb(const WCHAR* name, unsigned long addr, void* user)
1745 struct macho_sync* ms = user;
1747 TRACE("(%s, 0x%08lx, %p)\n", debugstr_w(name), addr, user);
1748 macho_search_and_load_file(ms->pcs, name, addr, &ms->macho_info);
1749 return TRUE;
1752 /******************************************************************
1753 * macho_synchronize_module_list
1755 * Rescans the debuggee's modules list and synchronizes it with
1756 * the one from 'pcs', ie:
1757 * - if a module is in debuggee and not in pcs, it's loaded into pcs
1758 * - if a module is in pcs and not in debuggee, it's unloaded from pcs
1760 BOOL macho_synchronize_module_list(struct process* pcs)
1762 struct module* module;
1763 struct macho_sync ms;
1765 TRACE("(%p/%p)\n", pcs, pcs->handle);
1767 for (module = pcs->lmodules; module; module = module->next)
1769 if (module->type == DMT_MACHO && !module->is_virtual)
1770 module->format_info[DFI_MACHO]->u.macho_info->in_use = 0;
1773 ms.pcs = pcs;
1774 ms.macho_info.flags = MACHO_INFO_MODULE;
1775 if (!macho_enum_modules_internal(pcs, NULL, macho_enum_sync_cb, &ms))
1776 return FALSE;
1778 module = pcs->lmodules;
1779 while (module)
1781 if (module->type == DMT_MACHO && !module->is_virtual &&
1782 !module->format_info[DFI_MACHO]->u.macho_info->in_use &&
1783 !module->format_info[DFI_MACHO]->u.macho_info->is_loader)
1785 module_remove(pcs, module);
1786 /* restart all over */
1787 module = pcs->lmodules;
1789 else module = module->next;
1791 return TRUE;
1794 /******************************************************************
1795 * macho_search_loader
1797 * Lookup in a running Mach-O process the loader, and sets its Mach-O link
1798 * address (for accessing the list of loaded images) in pcs.
1799 * If flags is MACHO_INFO_MODULE, the module for the loader is also
1800 * added as a module into pcs.
1802 static BOOL macho_search_loader(struct process* pcs, struct macho_info* macho_info)
1804 WCHAR *loader = get_wine_loader_name(pcs);
1805 BOOL ret = FALSE;
1806 ULONG_PTR dyld_image_info_address;
1807 union wine_all_image_infos image_infos;
1808 union wine_image_info image_info;
1809 uint32_t len;
1810 char path[PATH_MAX];
1811 BOOL got_path = FALSE;
1813 if (pcs->is_64bit)
1814 len = sizeof(image_infos.infos64);
1815 else
1816 len = sizeof(image_infos.infos32);
1817 dyld_image_info_address = get_dyld_image_info_address(pcs);
1818 if (dyld_image_info_address &&
1819 ReadProcessMemory(pcs->handle, (void*)dyld_image_info_address, &image_infos, len, NULL))
1821 if (pcs->is_64bit)
1822 len = sizeof(image_info.info64);
1823 else
1825 struct dyld_all_image_infos32 temp = image_infos.infos32;
1826 image_infos.infos64.infoArrayCount = temp.infoArrayCount;
1827 image_infos.infos64.infoArray = temp.infoArray;
1828 len = sizeof(image_info.info32);
1830 if (image_infos.infos64.infoArray && image_infos.infos64.infoArrayCount &&
1831 ReadProcessMemory(pcs->handle, (void*)image_infos.infos64.infoArray, &image_info, len, NULL))
1833 if (!pcs->is_64bit)
1835 struct dyld_image_info32 temp = image_info.info32;
1836 image_info.info64.imageLoadAddress = temp.imageLoadAddress;
1837 image_info.info64.imageFilePath = temp.imageFilePath;
1839 for (len = sizeof(path); image_info.info64.imageFilePath && len > 0; len /= 2)
1841 if (ReadProcessMemory(pcs->handle, (void*)image_info.info64.imageFilePath, path, len, NULL))
1843 path[len - 1] = 0;
1844 got_path = TRUE;
1845 TRACE("got executable path from target's dyld image info: %s\n", debugstr_a(path));
1846 break;
1852 /* If we couldn't get the executable path from the target process, try our
1853 own. It will almost always be the same. */
1854 if (!got_path)
1856 len = sizeof(path);
1857 if (!_NSGetExecutablePath(path, &len))
1859 got_path = TRUE;
1860 TRACE("using own executable path: %s\n", debugstr_a(path));
1864 if (got_path)
1866 WCHAR* pathW;
1868 len = MultiByteToWideChar(CP_UNIXCP, 0, path, -1, NULL, 0);
1869 pathW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1870 if (pathW)
1872 MultiByteToWideChar(CP_UNIXCP, 0, path, -1, pathW, len);
1873 ret = macho_load_file(pcs, pathW, 0, macho_info);
1874 HeapFree(GetProcessHeap(), 0, pathW);
1878 if (!ret)
1879 ret = macho_search_and_load_file(pcs, loader, 0, macho_info);
1880 heap_free(loader);
1881 return ret;
1884 /******************************************************************
1885 * macho_read_wine_loader_dbg_info
1887 * Try to find a decent wine executable which could have loaded the debuggee
1889 BOOL macho_read_wine_loader_dbg_info(struct process* pcs)
1891 struct macho_info macho_info;
1893 TRACE("(%p/%p)\n", pcs, pcs->handle);
1894 macho_info.flags = MACHO_INFO_DEBUG_HEADER | MACHO_INFO_MODULE;
1895 if (!macho_search_loader(pcs, &macho_info)) return FALSE;
1896 macho_info.module->format_info[DFI_MACHO]->u.macho_info->is_loader = 1;
1897 module_set_module(macho_info.module, S_WineLoaderW);
1898 return (pcs->dbg_hdr_addr = macho_info.dbg_hdr_addr) != 0;
1901 /******************************************************************
1902 * macho_enum_modules
1904 * Enumerates the Mach-O loaded modules from a running target (hProc)
1905 * This function doesn't require that someone has called SymInitialize
1906 * on this very process.
1908 BOOL macho_enum_modules(HANDLE hProc, enum_modules_cb cb, void* user)
1910 struct process pcs;
1911 struct macho_info macho_info;
1912 BOOL ret;
1914 TRACE("(%p, %p, %p)\n", hProc, cb, user);
1915 memset(&pcs, 0, sizeof(pcs));
1916 pcs.handle = hProc;
1917 macho_info.flags = MACHO_INFO_DEBUG_HEADER | MACHO_INFO_NAME;
1918 if (!macho_search_loader(&pcs, &macho_info)) return FALSE;
1919 pcs.dbg_hdr_addr = macho_info.dbg_hdr_addr;
1920 ret = macho_enum_modules_internal(&pcs, macho_info.module_name, cb, user);
1921 HeapFree(GetProcessHeap(), 0, (char*)macho_info.module_name);
1922 return ret;
1925 struct macho_load
1927 struct process* pcs;
1928 struct macho_info macho_info;
1929 const WCHAR* name;
1930 BOOL ret;
1933 /******************************************************************
1934 * macho_load_cb
1936 * Callback for macho_load_module, used to walk the list of loaded
1937 * modules.
1939 static BOOL macho_load_cb(const WCHAR* name, unsigned long addr, void* user)
1941 struct macho_load* ml = user;
1942 const WCHAR* p;
1944 TRACE("(%s, 0x%08lx, %p)\n", debugstr_w(name), addr, user);
1946 /* memcmp is needed for matches when bufstr contains also version information
1947 * ml->name: libc.so, name: libc.so.6.0
1949 p = strrchrW(name, '/');
1950 if (!p++) p = name;
1951 if (!memcmp(p, ml->name, lstrlenW(ml->name) * sizeof(WCHAR)))
1953 ml->ret = macho_search_and_load_file(ml->pcs, name, addr, &ml->macho_info);
1954 return FALSE;
1956 return TRUE;
1959 /******************************************************************
1960 * macho_load_module
1962 * Loads a Mach-O module and stores it in process' module list.
1963 * Also, find module real name and load address from
1964 * the real loaded modules list in pcs address space.
1966 struct module* macho_load_module(struct process* pcs, const WCHAR* name, unsigned long addr)
1968 struct macho_load ml;
1970 TRACE("(%p/%p, %s, 0x%08lx)\n", pcs, pcs->handle, debugstr_w(name), addr);
1972 ml.macho_info.flags = MACHO_INFO_MODULE;
1973 ml.ret = FALSE;
1975 if (pcs->dbg_hdr_addr) /* we're debugging a live target */
1977 ml.pcs = pcs;
1978 /* do only the lookup from the filename, not the path (as we lookup module
1979 * name in the process' loaded module list)
1981 ml.name = strrchrW(name, '/');
1982 if (!ml.name++) ml.name = name;
1983 ml.ret = FALSE;
1985 if (!macho_enum_modules_internal(pcs, NULL, macho_load_cb, &ml))
1986 return NULL;
1988 else if (addr)
1990 ml.name = name;
1991 ml.ret = macho_search_and_load_file(pcs, ml.name, addr, &ml.macho_info);
1993 if (!ml.ret) return NULL;
1994 assert(ml.macho_info.module);
1995 return ml.macho_info.module;
1998 #else /* HAVE_MACH_O_LOADER_H */
2000 BOOL macho_find_section(struct image_file_map* ifm, const char* segname, const char* sectname, struct image_section_map* ism)
2002 return FALSE;
2005 const char* macho_map_section(struct image_section_map* ism)
2007 return NULL;
2010 void macho_unmap_section(struct image_section_map* ism)
2014 DWORD_PTR macho_get_map_rva(const struct image_section_map* ism)
2016 return 0;
2019 unsigned macho_get_map_size(const struct image_section_map* ism)
2021 return 0;
2024 BOOL macho_synchronize_module_list(struct process* pcs)
2026 return FALSE;
2029 BOOL macho_fetch_file_info(HANDLE process, const WCHAR* name, unsigned long load_addr, DWORD_PTR* base,
2030 DWORD* size, DWORD* checksum)
2032 return FALSE;
2035 BOOL macho_read_wine_loader_dbg_info(struct process* pcs)
2037 return FALSE;
2040 BOOL macho_enum_modules(HANDLE hProc, enum_modules_cb cb, void* user)
2042 return FALSE;
2045 struct module* macho_load_module(struct process* pcs, const WCHAR* name, unsigned long addr)
2047 return NULL;
2050 BOOL macho_load_debug_info(struct process *pcs, struct module* module)
2052 return FALSE;
2054 #endif /* HAVE_MACH_O_LOADER_H */