xref: /reactos/dll/win32/dbghelp/macho_module.c (revision 19b18ce2)
1 /*
2  * File macho_module.c - processing of Mach-O files
3  *      Originally based on elf_module.c
4  *
5  * Copyright (C) 1996, Eric Youngdale.
6  *               1999-2007 Eric Pouech
7  *               2009 Ken Thomases, CodeWeavers Inc.
8  *
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.
13  *
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.
18  *
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
22  */
23 
24 #include "config.h"
25 #include "wine/port.h"
26 
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 #undef DPRINTF
35 #endif
36 
37 #include <stdio.h>
38 #include <assert.h>
39 #include <stdarg.h>
40 #include <errno.h>
41 #ifdef HAVE_SYS_STAT_H
42 # include <sys/stat.h>
43 #endif
44 #ifdef HAVE_SYS_MMAN_H
45 # include <sys/mman.h>
46 #endif
47 
48 #include "ntstatus.h"
49 #define WIN32_NO_STATUS
50 #include "dbghelp_private.h"
51 #include "winternl.h"
52 #include "wine/library.h"
53 #include "wine/debug.h"
54 #include "image_private.h"
55 
56 #ifdef HAVE_MACH_O_LOADER_H
57 
58 #include <mach-o/fat.h>
59 #include <mach-o/loader.h>
60 #include <mach-o/nlist.h>
61 #include <mach-o/dyld.h>
62 
63 #ifdef HAVE_MACH_O_DYLD_IMAGES_H
64 #include <mach-o/dyld_images.h>
65 #else
66 struct dyld_image_info {
67     const struct mach_header *imageLoadAddress;
68     const char               *imageFilePath;
69     uintptr_t                 imageFileModDate;
70 };
71 
72 struct dyld_all_image_infos {
73     uint32_t                      version;
74     uint32_t                      infoArrayCount;
75     const struct dyld_image_info *infoArray;
76     void*                         notification;
77     int                           processDetachedFromSharedRegion;
78 };
79 #endif
80 
81 #ifdef WORDS_BIGENDIAN
82 #define swap_ulong_be_to_host(n) (n)
83 #else
84 #define swap_ulong_be_to_host(n) (RtlUlongByteSwap(n))
85 #endif
86 
87 WINE_DEFAULT_DEBUG_CHANNEL(dbghelp_macho);
88 
89 
90 #ifdef _WIN64
91 typedef struct segment_command_64   macho_segment_command;
92 typedef struct nlist_64             macho_nlist;
93 
94 #define TARGET_CPU_TYPE         CPU_TYPE_X86_64
95 #define TARGET_MH_MAGIC         MH_MAGIC_64
96 #define TARGET_SEGMENT_COMMAND  LC_SEGMENT_64
97 #else
98 typedef struct segment_command      macho_segment_command;
99 typedef struct nlist                macho_nlist;
100 
101 #define TARGET_CPU_TYPE         CPU_TYPE_X86
102 #define TARGET_MH_MAGIC         MH_MAGIC
103 #define TARGET_SEGMENT_COMMAND  LC_SEGMENT
104 #endif
105 
106 
107 /* Bitmask for Mach-O image header flags indicating that the image is in dyld's
108    shared cached.  That implies that its segments are mapped non-contiguously.
109    This value isn't defined anywhere in headers.  It's used in dyld and in
110    debuggers which support OS X as a magic number.
111 
112    The flag also isn't set in the on-disk image file.  It's only set in
113    memory by dyld. */
114 #define MACHO_DYLD_IN_SHARED_CACHE 0x80000000
115 
116 
117 #define UUID_STRING_LEN 37 /* 16 bytes at 2 hex digits apiece, 4 dashes, and the null terminator */
118 
119 
120 struct macho_module_info
121 {
122     struct image_file_map       file_map;
123     unsigned long               load_addr;
124     unsigned short              in_use : 1,
125                                 is_loader : 1;
126 };
127 
128 struct section_info
129 {
130     BOOL            split_segs;
131     unsigned int    section_index;
132 };
133 
134 #define MACHO_INFO_DEBUG_HEADER   0x0001
135 #define MACHO_INFO_MODULE         0x0002
136 #define MACHO_INFO_NAME           0x0004
137 
138 struct macho_info
139 {
140     unsigned                    flags;          /* IN  one (or several) of the MACHO_INFO constants */
141     unsigned long               dbg_hdr_addr;   /* OUT address of debug header (if MACHO_INFO_DEBUG_HEADER is set) */
142     struct module*              module;         /* OUT loaded module (if MACHO_INFO_MODULE is set) */
143     const WCHAR*                module_name;    /* OUT found module name (if MACHO_INFO_NAME is set) */
144 };
145 
146 static void macho_unmap_file(struct image_file_map* fmap);
147 
148 static char* format_uuid(const uint8_t uuid[16], char out[UUID_STRING_LEN])
149 {
150     sprintf(out, "%02X%02X%02X%02X-%02X%02X-%02X%02X-%02X%02X-%02X%02X%02X%02X%02X%02X",
151             uuid[0], uuid[1], uuid[2], uuid[3], uuid[4], uuid[5], uuid[6], uuid[7],
152             uuid[8], uuid[9], uuid[10], uuid[11], uuid[12], uuid[13], uuid[14], uuid[15]);
153     return out;
154 }
155 
156 /******************************************************************
157  *              macho_calc_range
158  *
159  * For a range (offset & length) of a single architecture within
160  * a Mach-O file, calculate the page-aligned range of the whole file
161  * that encompasses it.  For a fat binary, the architecture will
162  * itself be offset within the file, so take that into account.
163  */
164 static void macho_calc_range(const struct macho_file_map* fmap, unsigned long offset,
165                              unsigned long len, unsigned long* out_aligned_offset,
166                              unsigned long* out_aligned_end, unsigned long* out_aligned_len,
167                              unsigned long* out_misalign)
168 {
169     unsigned long pagemask = sysconf( _SC_PAGESIZE ) - 1;
170     unsigned long file_offset, misalign;
171 
172     file_offset = fmap->arch_offset + offset;
173     misalign = file_offset & pagemask;
174     *out_aligned_offset = file_offset - misalign;
175     *out_aligned_end = (file_offset + len + pagemask) & ~pagemask;
176     if (out_aligned_len)
177         *out_aligned_len = *out_aligned_end - *out_aligned_offset;
178     if (out_misalign)
179         *out_misalign = misalign;
180 }
181 
182 /******************************************************************
183  *              macho_map_range
184  *
185  * Maps a range (offset, length in bytes) from a Mach-O file into memory
186  */
187 static const char* macho_map_range(const struct macho_file_map* fmap, unsigned long offset, unsigned long len,
188                                    const char** base)
189 {
190     unsigned long   misalign, aligned_offset, aligned_map_end, map_size;
191     const void*     aligned_ptr;
192 
193     TRACE("(%p/%d, 0x%08lx, 0x%08lx)\n", fmap, fmap->fd, offset, len);
194 
195     macho_calc_range(fmap, offset, len, &aligned_offset, &aligned_map_end,
196                      &map_size, &misalign);
197 
198     aligned_ptr = mmap(NULL, map_size, PROT_READ, MAP_PRIVATE, fmap->fd, aligned_offset);
199 
200     TRACE("Mapped (0x%08lx - 0x%08lx) to %p\n", aligned_offset, aligned_map_end, aligned_ptr);
201 
202     if (aligned_ptr == MAP_FAILED) return IMAGE_NO_MAP;
203     if (base)
204         *base = aligned_ptr;
205     return (const char*)aligned_ptr + misalign;
206 }
207 
208 /******************************************************************
209  *              macho_unmap_range
210  *
211  * Unmaps a range (offset, length in bytes) of a Mach-O file from memory
212  */
213 static void macho_unmap_range(const char** base, const void** mapped, const struct macho_file_map* fmap,
214                               unsigned long offset, unsigned long len)
215 {
216     TRACE("(%p, %p, %p/%d, 0x%08lx, 0x%08lx)\n", base, mapped, fmap, fmap->fd, offset, len);
217 
218     if ((mapped && *mapped != IMAGE_NO_MAP) || (base && *base != IMAGE_NO_MAP))
219     {
220         unsigned long   misalign, aligned_offset, aligned_map_end, map_size;
221         void*           aligned_ptr;
222 
223         macho_calc_range(fmap, offset, len, &aligned_offset, &aligned_map_end,
224                          &map_size, &misalign);
225 
226         if (mapped)
227             aligned_ptr = (char*)*mapped - misalign;
228         else
229             aligned_ptr = (void*)*base;
230         if (munmap(aligned_ptr, map_size) < 0)
231             WARN("Couldn't unmap the range\n");
232         TRACE("Unmapped (0x%08lx - 0x%08lx) from %p - %p\n", aligned_offset, aligned_map_end, aligned_ptr, (char*)aligned_ptr + map_size);
233         if (mapped)
234             *mapped = IMAGE_NO_MAP;
235         if (base)
236             *base = IMAGE_NO_MAP;
237     }
238 }
239 
240 /******************************************************************
241  *              macho_map_ranges
242  *
243  * Maps two ranges (offset, length in bytes) from a Mach-O file
244  * into memory.  If the two ranges overlap, use one mmap so that
245  * the munmap doesn't fragment the mapping.
246  */
247 static BOOL macho_map_ranges(const struct macho_file_map* fmap,
248                              unsigned long offset1, unsigned long len1,
249                              unsigned long offset2, unsigned long len2,
250                              const void** mapped1, const void** mapped2)
251 {
252     unsigned long aligned_offset1, aligned_map_end1;
253     unsigned long aligned_offset2, aligned_map_end2;
254 
255     TRACE("(%p/%d, 0x%08lx, 0x%08lx, 0x%08lx, 0x%08lx, %p, %p)\n", fmap, fmap->fd,
256             offset1, len1, offset2, len2, mapped1, mapped2);
257 
258     macho_calc_range(fmap, offset1, len1, &aligned_offset1, &aligned_map_end1, NULL, NULL);
259     macho_calc_range(fmap, offset2, len2, &aligned_offset2, &aligned_map_end2, NULL, NULL);
260 
261     if (aligned_map_end1 < aligned_offset2 || aligned_map_end2 < aligned_offset1)
262     {
263         *mapped1 = macho_map_range(fmap, offset1, len1, NULL);
264         if (*mapped1 != IMAGE_NO_MAP)
265         {
266             *mapped2 = macho_map_range(fmap, offset2, len2, NULL);
267             if (*mapped2 == IMAGE_NO_MAP)
268                 macho_unmap_range(NULL, mapped1, fmap, offset1, len1);
269         }
270     }
271     else
272     {
273         if (offset1 < offset2)
274         {
275             *mapped1 = macho_map_range(fmap, offset1, offset2 + len2 - offset1, NULL);
276             if (*mapped1 != IMAGE_NO_MAP)
277                 *mapped2 = (const char*)*mapped1 + offset2 - offset1;
278         }
279         else
280         {
281             *mapped2 = macho_map_range(fmap, offset2, offset1 + len1 - offset2, NULL);
282             if (*mapped2 != IMAGE_NO_MAP)
283                 *mapped1 = (const char*)*mapped2 + offset1 - offset2;
284         }
285     }
286 
287     TRACE(" => %p, %p\n", *mapped1, *mapped2);
288 
289     return (*mapped1 != IMAGE_NO_MAP) && (*mapped2 != IMAGE_NO_MAP);
290 }
291 
292 /******************************************************************
293  *              macho_unmap_ranges
294  *
295  * Unmaps two ranges (offset, length in bytes) of a Mach-O file
296  * from memory.  Use for ranges which were mapped by
297  * macho_map_ranges.
298  */
299 static void macho_unmap_ranges(const struct macho_file_map* fmap,
300                                unsigned long offset1, unsigned long len1,
301                                unsigned long offset2, unsigned long len2,
302                                const void** mapped1, const void** mapped2)
303 {
304     unsigned long   aligned_offset1, aligned_map_end1;
305     unsigned long   aligned_offset2, aligned_map_end2;
306 
307     TRACE("(%p/%d, 0x%08lx, 0x%08lx, 0x%08lx, 0x%08lx, %p/%p, %p/%p)\n", fmap, fmap->fd,
308             offset1, len1, offset2, len2, mapped1, *mapped1, mapped2, *mapped2);
309 
310     macho_calc_range(fmap, offset1, len1, &aligned_offset1, &aligned_map_end1, NULL, NULL);
311     macho_calc_range(fmap, offset2, len2, &aligned_offset2, &aligned_map_end2, NULL, NULL);
312 
313     if (aligned_map_end1 < aligned_offset2 || aligned_map_end2 < aligned_offset1)
314     {
315         macho_unmap_range(NULL, mapped1, fmap, offset1, len1);
316         macho_unmap_range(NULL, mapped2, fmap, offset2, len2);
317     }
318     else
319     {
320         if (offset1 < offset2)
321         {
322             macho_unmap_range(NULL, mapped1, fmap, offset1, offset2 + len2 - offset1);
323             *mapped2 = IMAGE_NO_MAP;
324         }
325         else
326         {
327             macho_unmap_range(NULL, mapped2, fmap, offset2, offset1 + len1 - offset2);
328             *mapped1 = IMAGE_NO_MAP;
329         }
330     }
331 }
332 
333 /******************************************************************
334  *              macho_find_section
335  */
336 BOOL macho_find_section(struct image_file_map* ifm, const char* segname, const char* sectname, struct image_section_map* ism)
337 {
338     struct macho_file_map* fmap;
339     unsigned i;
340     char tmp[sizeof(fmap->sect[0].section->sectname)];
341 
342     /* Other parts of dbghelp use section names like ".eh_frame".  Mach-O uses
343        names like "__eh_frame".  Convert those. */
344     if (sectname[0] == '.')
345     {
346         lstrcpynA(tmp, "__", sizeof(tmp));
347         lstrcpynA(tmp + 2, sectname + 1, sizeof(tmp) - 2);
348         sectname = tmp;
349     }
350 
351     while (ifm)
352     {
353         fmap = &ifm->u.macho;
354         for (i = 0; i < fmap->num_sections; i++)
355         {
356             if (!fmap->sect[i].ignored &&
357                 strcmp(fmap->sect[i].section->sectname, sectname) == 0 &&
358                 (!segname || strcmp(fmap->sect[i].section->segname, segname) == 0))
359             {
360                 ism->fmap = ifm;
361                 ism->sidx = i;
362                 return TRUE;
363             }
364         }
365         ifm = fmap->dsym;
366     }
367 
368     ism->fmap = NULL;
369     ism->sidx = -1;
370     return FALSE;
371 }
372 
373 /******************************************************************
374  *              macho_map_section
375  */
376 const char* macho_map_section(struct image_section_map* ism)
377 {
378     struct macho_file_map* fmap = &ism->fmap->u.macho;
379 
380     assert(ism->fmap->modtype == DMT_MACHO);
381     if (ism->sidx < 0 || ism->sidx >= ism->fmap->u.macho.num_sections || fmap->sect[ism->sidx].ignored)
382         return IMAGE_NO_MAP;
383 
384     return macho_map_range(fmap, fmap->sect[ism->sidx].section->offset, fmap->sect[ism->sidx].section->size,
385                            &fmap->sect[ism->sidx].mapped);
386 }
387 
388 /******************************************************************
389  *              macho_unmap_section
390  */
391 void macho_unmap_section(struct image_section_map* ism)
392 {
393     struct macho_file_map* fmap = &ism->fmap->u.macho;
394 
395     if (ism->sidx >= 0 && ism->sidx < fmap->num_sections && fmap->sect[ism->sidx].mapped != IMAGE_NO_MAP)
396     {
397         macho_unmap_range(&fmap->sect[ism->sidx].mapped, NULL, fmap, fmap->sect[ism->sidx].section->offset,
398                           fmap->sect[ism->sidx].section->size);
399     }
400 }
401 
402 /******************************************************************
403  *              macho_get_map_rva
404  */
405 DWORD_PTR macho_get_map_rva(const struct image_section_map* ism)
406 {
407     if (ism->sidx < 0 || ism->sidx >= ism->fmap->u.macho.num_sections ||
408         ism->fmap->u.macho.sect[ism->sidx].ignored)
409         return 0;
410     return ism->fmap->u.macho.sect[ism->sidx].section->addr - ism->fmap->u.macho.segs_start;
411 }
412 
413 /******************************************************************
414  *              macho_get_map_size
415  */
416 unsigned macho_get_map_size(const struct image_section_map* ism)
417 {
418     if (ism->sidx < 0 || ism->sidx >= ism->fmap->u.macho.num_sections ||
419         ism->fmap->u.macho.sect[ism->sidx].ignored)
420         return 0;
421     return ism->fmap->u.macho.sect[ism->sidx].section->size;
422 }
423 
424 /******************************************************************
425  *              macho_map_load_commands
426  *
427  * Maps the load commands from a Mach-O file into memory
428  */
429 static const struct load_command* macho_map_load_commands(struct macho_file_map* fmap)
430 {
431     if (fmap->load_commands == IMAGE_NO_MAP)
432     {
433         fmap->load_commands = (const struct load_command*) macho_map_range(
434                 fmap, sizeof(fmap->mach_header), fmap->mach_header.sizeofcmds, NULL);
435         TRACE("Mapped load commands: %p\n", fmap->load_commands);
436     }
437 
438     return fmap->load_commands;
439 }
440 
441 /******************************************************************
442  *              macho_unmap_load_commands
443  *
444  * Unmaps the load commands of a Mach-O file from memory
445  */
446 static void macho_unmap_load_commands(struct macho_file_map* fmap)
447 {
448     if (fmap->load_commands != IMAGE_NO_MAP)
449     {
450         TRACE("Unmapping load commands: %p\n", fmap->load_commands);
451         macho_unmap_range(NULL, (const void**)&fmap->load_commands, fmap,
452                     sizeof(fmap->mach_header), fmap->mach_header.sizeofcmds);
453     }
454 }
455 
456 /******************************************************************
457  *              macho_next_load_command
458  *
459  * Advance to the next load command
460  */
461 static const struct load_command* macho_next_load_command(const struct load_command* lc)
462 {
463     return (const struct load_command*)((const char*)lc + lc->cmdsize);
464 }
465 
466 /******************************************************************
467  *              macho_enum_load_commands
468  *
469  * Enumerates the load commands for a Mach-O file, selecting by
470  * the command type, calling a callback for each.  If the callback
471  * returns <0, that indicates an error.  If it returns >0, that means
472  * it's not interested in getting any more load commands.
473  * If this function returns <0, that's an error produced by the
474  * callback.  If >=0, that's the count of load commands successfully
475  * processed.
476  */
477 static int macho_enum_load_commands(struct macho_file_map* fmap, unsigned cmd,
478                                     int (*cb)(struct macho_file_map*, const struct load_command*, void*),
479                                     void* user)
480 {
481     const struct load_command* lc;
482     int i;
483     int count = 0;
484 
485     TRACE("(%p/%d, %u, %p, %p)\n", fmap, fmap->fd, cmd, cb, user);
486 
487     if ((lc = macho_map_load_commands(fmap)) == IMAGE_NO_MAP) return -1;
488 
489     TRACE("%d total commands\n", fmap->mach_header.ncmds);
490 
491     for (i = 0; i < fmap->mach_header.ncmds; i++, lc = macho_next_load_command(lc))
492     {
493         int result;
494 
495         if (cmd && cmd != lc->cmd) continue;
496         count++;
497 
498         result = cb(fmap, 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;
501     }
502 
503     return count;
504 }
505 
506 /******************************************************************
507  *              macho_count_sections
508  *
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.
512  */
513 static int macho_count_sections(struct macho_file_map* fmap, const struct load_command* lc, void* user)
514 {
515     const macho_segment_command* sc = (const macho_segment_command*)lc;
516 
517     TRACE("(%p/%d, %p, %p) segment %s\n", fmap, fmap->fd, lc, user, debugstr_an(sc->segname, sizeof(sc->segname)));
518 
519     fmap->num_sections += sc->nsects;
520     return 0;
521 }
522 
523 /******************************************************************
524  *              macho_load_section_info
525  *
526  * Callback for macho_enum_load_commands.  Accumulates the address
527  * range covered by the segments of a Mach-O file and builds the
528  * section map.  All commands are expected to be of LC_SEGMENT[_64] type.
529  */
530 static int macho_load_section_info(struct macho_file_map* fmap, const struct load_command* lc, void* user)
531 {
532     const macho_segment_command*    sc = (const macho_segment_command*)lc;
533     struct section_info*            info = user;
534     BOOL                            ignore;
535     const macho_section*            section;
536     int                             i;
537     unsigned long                   tmp, page_mask = sysconf( _SC_PAGESIZE ) - 1;
538 
539     TRACE("(%p/%d, %p, %p) before: 0x%08lx - 0x%08lx\n", fmap, fmap->fd, lc, user,
540             (unsigned long)fmap->segs_start, (unsigned long)fmap->segs_size);
541     TRACE("Segment command vm: 0x%08lx - 0x%08lx\n", (unsigned long)sc->vmaddr,
542             (unsigned long)(sc->vmaddr + sc->vmsize));
543 
544     /* Images in the dyld shared cache have their segments mapped non-contiguously.
545        We don't know how to properly locate any of the segments other than __TEXT,
546        so ignore them. */
547     ignore = (info->split_segs && strcmp(sc->segname, SEG_TEXT));
548 
549     if (!strncmp(sc->segname, "WINE_", 5))
550         TRACE("Ignoring special Wine segment %s\n", debugstr_an(sc->segname, sizeof(sc->segname)));
551     else if (!strncmp(sc->segname, "__PAGEZERO", 10))
552         TRACE("Ignoring __PAGEZERO segment\n");
553     else if (ignore)
554         TRACE("Ignoring %s segment because image has split segments\n", sc->segname);
555     else
556     {
557         /* If this segment starts before previously-known earliest, record new earliest. */
558         if (sc->vmaddr < fmap->segs_start)
559             fmap->segs_start = sc->vmaddr;
560 
561         /* If this segment extends beyond previously-known furthest, record new furthest. */
562         tmp = (sc->vmaddr + sc->vmsize + page_mask) & ~page_mask;
563         if (fmap->segs_size < tmp) fmap->segs_size = tmp;
564 
565         TRACE("after: 0x%08lx - 0x%08lx\n", (unsigned long)fmap->segs_start, (unsigned long)fmap->segs_size);
566     }
567 
568     section = (const macho_section*)(sc + 1);
569     for (i = 0; i < sc->nsects; i++)
570     {
571         fmap->sect[info->section_index].section = &section[i];
572         fmap->sect[info->section_index].mapped = IMAGE_NO_MAP;
573         fmap->sect[info->section_index].ignored = ignore;
574         info->section_index++;
575     }
576 
577     return 0;
578 }
579 
580 /******************************************************************
581  *              find_uuid
582  *
583  * Callback for macho_enum_load_commands.  Records the UUID load
584  * command of a Mach-O file.
585  */
586 static int find_uuid(struct macho_file_map* fmap, const struct load_command* lc, void* user)
587 {
588     fmap->uuid = (const struct uuid_command*)lc;
589     return 1;
590 }
591 
592 /******************************************************************
593  *              reset_file_map
594  */
595 static inline void reset_file_map(struct image_file_map* ifm)
596 {
597     struct macho_file_map* fmap = &ifm->u.macho;
598 
599     fmap->fd = -1;
600     fmap->dsym = NULL;
601     fmap->load_commands = IMAGE_NO_MAP;
602     fmap->uuid = NULL;
603     fmap->num_sections = 0;
604     fmap->sect = NULL;
605 }
606 
607 /******************************************************************
608  *              macho_map_file
609  *
610  * Maps a Mach-O file into memory (and checks it's a real Mach-O file)
611  */
612 static BOOL macho_map_file(const WCHAR* filenameW, BOOL split_segs, struct image_file_map* ifm)
613 {
614     struct macho_file_map* fmap = &ifm->u.macho;
615     struct fat_header   fat_header;
616     struct stat         statbuf;
617     int                 i;
618     char*               filename;
619     unsigned            len;
620     struct section_info info;
621     BOOL                ret = FALSE;
622 
623     TRACE("(%s, %p)\n", debugstr_w(filenameW), fmap);
624 
625     reset_file_map(ifm);
626 
627     ifm->modtype = DMT_MACHO;
628 #ifdef _WIN64
629     ifm->addr_size = 64;
630 #else
631     ifm->addr_size = 32;
632 #endif
633 
634     len = WideCharToMultiByte(CP_UNIXCP, 0, filenameW, -1, NULL, 0, NULL, NULL);
635     if (!(filename = HeapAlloc(GetProcessHeap(), 0, len)))
636     {
637         WARN("failed to allocate filename buffer\n");
638         return FALSE;
639     }
640     WideCharToMultiByte(CP_UNIXCP, 0, filenameW, -1, filename, len, NULL, NULL);
641 
642     /* check that the file exists */
643     if (stat(filename, &statbuf) == -1 || S_ISDIR(statbuf.st_mode))
644     {
645         TRACE("stat() failed or %s is directory: %s\n", debugstr_a(filename), strerror(errno));
646         goto done;
647     }
648 
649     /* Now open the file, so that we can mmap() it. */
650     if ((fmap->fd = open(filename, O_RDONLY)) == -1)
651     {
652         TRACE("failed to open file %s: %d\n", debugstr_a(filename), errno);
653         goto done;
654     }
655 
656     if (read(fmap->fd, &fat_header, sizeof(fat_header)) != sizeof(fat_header))
657     {
658         TRACE("failed to read fat header: %d\n", errno);
659         goto done;
660     }
661     TRACE("... got possible fat header\n");
662 
663     /* Fat header is always in big-endian order. */
664     if (swap_ulong_be_to_host(fat_header.magic) == FAT_MAGIC)
665     {
666         int narch = swap_ulong_be_to_host(fat_header.nfat_arch);
667         for (i = 0; i < narch; i++)
668         {
669             struct fat_arch fat_arch;
670             if (read(fmap->fd, &fat_arch, sizeof(fat_arch)) != sizeof(fat_arch))
671                 goto done;
672             if (swap_ulong_be_to_host(fat_arch.cputype) == TARGET_CPU_TYPE)
673             {
674                 fmap->arch_offset = swap_ulong_be_to_host(fat_arch.offset);
675                 break;
676             }
677         }
678         if (i >= narch) goto done;
679         TRACE("... found target arch (%d)\n", TARGET_CPU_TYPE);
680     }
681     else
682     {
683         fmap->arch_offset = 0;
684         TRACE("... not a fat header\n");
685     }
686 
687     /* Individual architecture (standalone or within a fat file) is in its native byte order. */
688     lseek(fmap->fd, fmap->arch_offset, SEEK_SET);
689     if (read(fmap->fd, &fmap->mach_header, sizeof(fmap->mach_header)) != sizeof(fmap->mach_header))
690         goto done;
691     TRACE("... got possible Mach header\n");
692     /* and check for a Mach-O header */
693     if (fmap->mach_header.magic != TARGET_MH_MAGIC ||
694         fmap->mach_header.cputype != TARGET_CPU_TYPE) goto done;
695     /* Make sure the file type is one of the ones we expect. */
696     switch (fmap->mach_header.filetype)
697     {
698         case MH_EXECUTE:
699         case MH_DYLIB:
700         case MH_DYLINKER:
701         case MH_BUNDLE:
702         case MH_DSYM:
703             break;
704         default:
705             goto done;
706     }
707     TRACE("... verified Mach header\n");
708 
709     fmap->num_sections = 0;
710     if (macho_enum_load_commands(fmap, TARGET_SEGMENT_COMMAND, macho_count_sections, NULL) < 0)
711         goto done;
712     TRACE("%d sections\n", fmap->num_sections);
713 
714     fmap->sect = HeapAlloc(GetProcessHeap(), 0, fmap->num_sections * sizeof(fmap->sect[0]));
715     if (!fmap->sect)
716         goto done;
717 
718     fmap->segs_size = 0;
719     fmap->segs_start = ~0L;
720 
721     info.split_segs = split_segs;
722     info.section_index = 0;
723     if (macho_enum_load_commands(fmap, TARGET_SEGMENT_COMMAND, macho_load_section_info, &info) < 0)
724     {
725         fmap->num_sections = 0;
726         goto done;
727     }
728 
729     fmap->segs_size -= fmap->segs_start;
730     TRACE("segs_start: 0x%08lx, segs_size: 0x%08lx\n", (unsigned long)fmap->segs_start,
731             (unsigned long)fmap->segs_size);
732 
733     if (macho_enum_load_commands(fmap, LC_UUID, find_uuid, NULL) < 0)
734         goto done;
735     if (fmap->uuid)
736     {
737         char uuid_string[UUID_STRING_LEN];
738         TRACE("UUID %s\n", format_uuid(fmap->uuid->uuid, uuid_string));
739     }
740     else
741         TRACE("no UUID found\n");
742 
743     ret = TRUE;
744 done:
745     if (!ret)
746         macho_unmap_file(ifm);
747     HeapFree(GetProcessHeap(), 0, filename);
748     return ret;
749 }
750 
751 /******************************************************************
752  *              macho_unmap_file
753  *
754  * Unmaps a Mach-O file from memory (previously mapped with macho_map_file)
755  */
756 static void macho_unmap_file(struct image_file_map* ifm)
757 {
758     struct image_file_map* cursor;
759 
760     TRACE("(%p/%d)\n", ifm, ifm->u.macho.fd);
761 
762     cursor = ifm;
763     while (cursor)
764     {
765         struct image_file_map* next;
766 
767         if (ifm->u.macho.fd != -1)
768         {
769             struct image_section_map ism;
770 
771             ism.fmap = ifm;
772             for (ism.sidx = 0; ism.sidx < ifm->u.macho.num_sections; ism.sidx++)
773                 macho_unmap_section(&ism);
774 
775             HeapFree(GetProcessHeap(), 0, ifm->u.macho.sect);
776             macho_unmap_load_commands(&ifm->u.macho);
777             close(ifm->u.macho.fd);
778             ifm->u.macho.fd = -1;
779         }
780 
781         next = cursor->u.macho.dsym;
782         if (cursor != ifm)
783             HeapFree(GetProcessHeap(), 0, cursor);
784         cursor = next;
785     }
786 }
787 
788 /******************************************************************
789  *              macho_sect_is_code
790  *
791  * Checks if a section, identified by sectidx which is a 1-based
792  * index into the sections of all segments, in order of load
793  * commands, contains code.
794  */
795 static BOOL macho_sect_is_code(struct macho_file_map* fmap, unsigned char sectidx)
796 {
797     BOOL ret;
798 
799     TRACE("(%p/%d, %u)\n", fmap, fmap->fd, sectidx);
800 
801     if (!sectidx) return FALSE;
802 
803     sectidx--; /* convert from 1-based to 0-based */
804     if (sectidx >= fmap->num_sections || fmap->sect[sectidx].ignored) return FALSE;
805 
806     ret = (!(fmap->sect[sectidx].section->flags & SECTION_TYPE) &&
807            (fmap->sect[sectidx].section->flags & (S_ATTR_PURE_INSTRUCTIONS|S_ATTR_SOME_INSTRUCTIONS)));
808     TRACE("-> %d\n", ret);
809     return ret;
810 }
811 
812 struct symtab_elt
813 {
814     struct hash_table_elt       ht_elt;
815     struct symt_compiland*      compiland;
816     unsigned long               addr;
817     unsigned char               is_code:1,
818                                 is_public:1,
819                                 is_global:1,
820                                 used:1;
821 };
822 
823 struct macho_debug_info
824 {
825     struct macho_file_map*      fmap;
826     struct module*              module;
827     struct pool                 pool;
828     struct hash_table           ht_symtab;
829 };
830 
831 /******************************************************************
832  *              macho_stabs_def_cb
833  *
834  * Callback for stabs_parse.  Collect symbol definitions.
835  */
836 static void macho_stabs_def_cb(struct module* module, unsigned long load_offset,
837                                const char* name, unsigned long offset,
838                                BOOL is_public, BOOL is_global, unsigned char sectidx,
839                                struct symt_compiland* compiland, void* user)
840 {
841     struct macho_debug_info*    mdi = user;
842     struct symtab_elt*          ste;
843 
844     TRACE("(%p, 0x%08lx, %s, 0x%08lx, %d, %d, %u, %p, %p/%p/%d)\n", module, load_offset,
845             debugstr_a(name), offset, is_public, is_global, sectidx,
846             compiland, mdi, mdi->fmap, mdi->fmap->fd);
847 
848     /* Defer the creation of new non-debugging symbols until after we've
849      * finished parsing the stabs. */
850     ste                 = pool_alloc(&mdi->pool, sizeof(*ste));
851     ste->ht_elt.name    = pool_strdup(&mdi->pool, name);
852     ste->compiland      = compiland;
853     ste->addr           = load_offset + offset;
854     ste->is_code        = !!macho_sect_is_code(mdi->fmap, sectidx);
855     ste->is_public      = !!is_public;
856     ste->is_global      = !!is_global;
857     ste->used           = 0;
858     hash_table_add(&mdi->ht_symtab, &ste->ht_elt);
859 }
860 
861 /******************************************************************
862  *              macho_parse_symtab
863  *
864  * Callback for macho_enum_load_commands.  Processes the LC_SYMTAB
865  * load commands from the Mach-O file.
866  */
867 static int macho_parse_symtab(struct macho_file_map* fmap,
868                               const struct load_command* lc, void* user)
869 {
870     const struct symtab_command*    sc = (const struct symtab_command*)lc;
871     struct macho_debug_info*        mdi = user;
872     const macho_nlist*              stab;
873     const char*                     stabstr;
874     int                             ret = 0;
875 
876     TRACE("(%p/%d, %p, %p) %u syms at 0x%08x, strings 0x%08x - 0x%08x\n", fmap, fmap->fd, lc,
877             user, sc->nsyms, sc->symoff, sc->stroff, sc->stroff + sc->strsize);
878 
879     if (!macho_map_ranges(fmap, sc->symoff, sc->nsyms * sizeof(macho_nlist),
880             sc->stroff, sc->strsize, (const void**)&stab, (const void**)&stabstr))
881         return 0;
882 
883     if (!stabs_parse(mdi->module,
884                      mdi->module->format_info[DFI_MACHO]->u.macho_info->load_addr - fmap->segs_start,
885                      stab, sc->nsyms * sizeof(macho_nlist),
886                      stabstr, sc->strsize, macho_stabs_def_cb, mdi))
887         ret = -1;
888 
889     macho_unmap_ranges(fmap, sc->symoff, sc->nsyms * sizeof(macho_nlist),
890             sc->stroff, sc->strsize, (const void**)&stab, (const void**)&stabstr);
891 
892     return ret;
893 }
894 
895 /******************************************************************
896  *              macho_finish_stabs
897  *
898  * Integrate the non-debugging symbols we've gathered into the
899  * symbols that were generated during stabs parsing.
900  */
901 static void macho_finish_stabs(struct module* module, struct hash_table* ht_symtab)
902 {
903     struct hash_table_iter      hti_ours;
904     struct symtab_elt*          ste;
905     BOOL                        adjusted = FALSE;
906 
907     TRACE("(%p, %p)\n", module, ht_symtab);
908 
909     /* For each of our non-debugging symbols, see if it can provide some
910      * missing details to one of the module's known symbols. */
911     hash_table_iter_init(ht_symtab, &hti_ours, NULL);
912     while ((ste = hash_table_iter_up(&hti_ours)))
913     {
914         struct hash_table_iter  hti_modules;
915         void*                   ptr;
916         struct symt_ht*         sym;
917         struct symt_function*   func;
918         struct symt_data*       data;
919 
920         hash_table_iter_init(&module->ht_symbols, &hti_modules, ste->ht_elt.name);
921         while ((ptr = hash_table_iter_up(&hti_modules)))
922         {
923             sym = CONTAINING_RECORD(ptr, struct symt_ht, hash_elt);
924 
925             if (strcmp(sym->hash_elt.name, ste->ht_elt.name))
926                 continue;
927 
928             switch (sym->symt.tag)
929             {
930             case SymTagFunction:
931                 func = (struct symt_function*)sym;
932                 if (func->address == module->format_info[DFI_MACHO]->u.macho_info->load_addr)
933                 {
934                     TRACE("Adjusting function %p/%s!%s from 0x%08lx to 0x%08lx\n", func,
935                           debugstr_w(module->module.ModuleName), sym->hash_elt.name,
936                           func->address, ste->addr);
937                     func->address = ste->addr;
938                     adjusted = TRUE;
939                 }
940                 if (func->address == ste->addr)
941                     ste->used = 1;
942                 break;
943             case SymTagData:
944                 data = (struct symt_data*)sym;
945                 switch (data->kind)
946                 {
947                 case DataIsGlobal:
948                 case DataIsFileStatic:
949                     if (data->u.var.offset == module->format_info[DFI_MACHO]->u.macho_info->load_addr)
950                     {
951                         TRACE("Adjusting data symbol %p/%s!%s from 0x%08lx to 0x%08lx\n",
952                               data, debugstr_w(module->module.ModuleName), sym->hash_elt.name,
953                               data->u.var.offset, ste->addr);
954                         data->u.var.offset = ste->addr;
955                         adjusted = TRUE;
956                     }
957                     if (data->u.var.offset == ste->addr)
958                     {
959                         enum DataKind new_kind;
960 
961                         new_kind = ste->is_global ? DataIsGlobal : DataIsFileStatic;
962                         if (data->kind != new_kind)
963                         {
964                             WARN("Changing kind for %p/%s!%s from %d to %d\n", sym,
965                                  debugstr_w(module->module.ModuleName), sym->hash_elt.name,
966                                  (int)data->kind, (int)new_kind);
967                             data->kind = new_kind;
968                             adjusted = TRUE;
969                         }
970                         ste->used = 1;
971                     }
972                     break;
973                 default:;
974                 }
975                 break;
976             default:
977                 TRACE("Ignoring tag %u\n", sym->symt.tag);
978                 break;
979             }
980         }
981     }
982 
983     if (adjusted)
984     {
985         /* since we may have changed some addresses, mark the module to be resorted */
986         module->sortlist_valid = FALSE;
987     }
988 
989     /* Mark any of our non-debugging symbols which fall on an already-used
990      * address as "used".  This allows us to skip them in the next loop,
991      * below.  We do this in separate loops because symt_new_* marks the
992      * list as needing sorting and symt_find_nearest sorts if needed,
993      * causing thrashing. */
994     if (!(dbghelp_options & SYMOPT_PUBLICS_ONLY))
995     {
996         hash_table_iter_init(ht_symtab, &hti_ours, NULL);
997         while ((ste = hash_table_iter_up(&hti_ours)))
998         {
999             struct symt_ht* sym;
1000             ULONG64         addr;
1001 
1002             if (ste->used) continue;
1003 
1004             sym = symt_find_nearest(module, ste->addr);
1005             if (sym)
1006                 symt_get_address(&sym->symt, &addr);
1007             if (sym && ste->addr == addr)
1008             {
1009                 ULONG64 size = 0;
1010                 DWORD   kind = -1;
1011 
1012                 ste->used = 1;
1013 
1014                 /* If neither symbol has a correct size (ours never does), we
1015                  * consider them both to be markers.  No warning is needed in
1016                  * that case.
1017                  * Also, we check that we don't have two symbols, one local, the other
1018                  * global, which is legal.
1019                  */
1020                 symt_get_info(module, &sym->symt, TI_GET_LENGTH,   &size);
1021                 symt_get_info(module, &sym->symt, TI_GET_DATAKIND, &kind);
1022                 if (size && kind == (ste->is_global ? DataIsGlobal : DataIsFileStatic))
1023                     FIXME("Duplicate in %s: %s<%08lx> %s<%s-%s>\n",
1024                           debugstr_w(module->module.ModuleName),
1025                           ste->ht_elt.name, ste->addr,
1026                           sym->hash_elt.name,
1027                           wine_dbgstr_longlong(addr), wine_dbgstr_longlong(size));
1028             }
1029         }
1030     }
1031 
1032     /* For any of our remaining non-debugging symbols which have no match
1033      * among the module's known symbols, add them as new symbols. */
1034     hash_table_iter_init(ht_symtab, &hti_ours, NULL);
1035     while ((ste = hash_table_iter_up(&hti_ours)))
1036     {
1037         if (!(dbghelp_options & SYMOPT_PUBLICS_ONLY) && !ste->used)
1038         {
1039             if (ste->is_code)
1040             {
1041                 symt_new_function(module, ste->compiland, ste->ht_elt.name,
1042                     ste->addr, 0, NULL);
1043             }
1044             else
1045             {
1046                 struct location loc;
1047 
1048                 loc.kind = loc_absolute;
1049                 loc.reg = 0;
1050                 loc.offset = ste->addr;
1051                 symt_new_global_variable(module, ste->compiland, ste->ht_elt.name,
1052                                          !ste->is_global, loc, 0, NULL);
1053             }
1054 
1055             ste->used = 1;
1056         }
1057 
1058         if (ste->is_public && !(dbghelp_options & SYMOPT_NO_PUBLICS))
1059         {
1060             symt_new_public(module, ste->compiland, ste->ht_elt.name, ste->addr, 0);
1061         }
1062     }
1063 }
1064 
1065 /******************************************************************
1066  *              try_dsym
1067  *
1068  * Try to load a debug symbol file from the given path and check
1069  * if its UUID matches the UUID of an already-mapped file.  If so,
1070  * stash the file map in the "dsym" field of the file and return
1071  * TRUE.  If it can't be mapped or its UUID doesn't match, return
1072  * FALSE.
1073  */
1074 static BOOL try_dsym(const WCHAR* path, struct macho_file_map* fmap)
1075 {
1076     struct image_file_map dsym_ifm;
1077 
1078     if (macho_map_file(path, FALSE, &dsym_ifm))
1079     {
1080         char uuid_string[UUID_STRING_LEN];
1081 
1082         if (dsym_ifm.u.macho.uuid && !memcmp(dsym_ifm.u.macho.uuid->uuid, fmap->uuid->uuid, sizeof(fmap->uuid->uuid)))
1083         {
1084             TRACE("found matching debug symbol file at %s\n", debugstr_w(path));
1085             fmap->dsym = HeapAlloc(GetProcessHeap(), 0, sizeof(dsym_ifm));
1086             *fmap->dsym = dsym_ifm;
1087             return TRUE;
1088         }
1089 
1090         TRACE("candidate debug symbol file at %s has wrong UUID %s; ignoring\n", debugstr_w(path),
1091               format_uuid(dsym_ifm.u.macho.uuid->uuid, uuid_string));
1092 
1093         macho_unmap_file(&dsym_ifm);
1094     }
1095     else
1096         TRACE("couldn't map file at %s\n", debugstr_w(path));
1097 
1098     return FALSE;
1099 }
1100 
1101 /******************************************************************
1102  *              find_and_map_dsym
1103  *
1104  * Search for a debugging symbols file associated with a module and
1105  * map it.  First look for a .dSYM bundle next to the module file
1106  * (e.g. <path>.dSYM/Contents/Resources/DWARF/<basename of path>)
1107  * as produced by dsymutil.  Next, look for a .dwarf file next to
1108  * the module file (e.g. <path>.dwarf) as produced by
1109  * "dsymutil --flat".  Finally, use Spotlight to search for a
1110  * .dSYM bundle with the same UUID as the module file.
1111  */
1112 static void find_and_map_dsym(struct module* module)
1113 {
1114     static const WCHAR dot_dsym[] = {'.','d','S','Y','M',0};
1115     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};
1116     static const WCHAR dot_dwarf[] = {'.','d','w','a','r','f',0};
1117     struct macho_file_map* fmap = &module->format_info[DFI_MACHO]->u.macho_info->file_map.u.macho;
1118     const WCHAR* p;
1119     size_t len;
1120     WCHAR* path = NULL;
1121     char uuid_string[UUID_STRING_LEN];
1122     CFStringRef uuid_cfstring;
1123     CFStringRef query_string;
1124     MDQueryRef query = NULL;
1125 
1126     /* Without a UUID, we can't verify that any debug info file we find corresponds
1127        to this file.  Better to have no debug info than incorrect debug info. */
1128     if (!fmap->uuid)
1129         return;
1130 
1131     if ((p = strrchrW(module->module.LoadedImageName, '/')))
1132         p++;
1133     else
1134         p = module->module.LoadedImageName;
1135     len = strlenW(module->module.LoadedImageName) + strlenW(dot_dsym) + strlenW(dsym_subpath) + strlenW(p) + 1;
1136     path = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1137     if (!path)
1138         return;
1139     strcpyW(path, module->module.LoadedImageName);
1140     strcatW(path, dot_dsym);
1141     strcatW(path, dsym_subpath);
1142     strcatW(path, p);
1143 
1144     if (try_dsym(path, fmap))
1145         goto found;
1146 
1147     strcpyW(path + strlenW(module->module.LoadedImageName), dot_dwarf);
1148 
1149     if (try_dsym(path, fmap))
1150         goto found;
1151 
1152     format_uuid(fmap->uuid->uuid, uuid_string);
1153     uuid_cfstring = CFStringCreateWithCString(NULL, uuid_string, kCFStringEncodingASCII);
1154     query_string = CFStringCreateWithFormat(NULL, NULL, CFSTR("com_apple_xcode_dsym_uuids == \"%@\""), uuid_cfstring);
1155     CFRelease(uuid_cfstring);
1156     query = MDQueryCreate(NULL, query_string, NULL, NULL);
1157     CFRelease(query_string);
1158     MDQuerySetMaxCount(query, 1);
1159     if (MDQueryExecute(query, kMDQuerySynchronous) && MDQueryGetResultCount(query) >= 1)
1160     {
1161         MDItemRef item = (MDItemRef)MDQueryGetResultAtIndex(query, 0);
1162         CFStringRef item_path = MDItemCopyAttribute(item, kMDItemPath);
1163         if (item_path)
1164         {
1165             CFIndex item_path_len = CFStringGetLength(item_path);
1166             if (item_path_len + strlenW(dsym_subpath) + strlenW(p) >= len)
1167             {
1168                 HeapFree(GetProcessHeap(), 0, path);
1169                 len = item_path_len + strlenW(dsym_subpath) + strlenW(p) + 1;
1170                 path = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1171             }
1172             CFStringGetCharacters(item_path, CFRangeMake(0, item_path_len), (UniChar*)path);
1173             strcpyW(path + item_path_len, dsym_subpath);
1174             strcatW(path, p);
1175             CFRelease(item_path);
1176 
1177             if (try_dsym(path, fmap))
1178                 goto found;
1179         }
1180     }
1181 
1182 found:
1183     HeapFree(GetProcessHeap(), 0, path);
1184     if (query) CFRelease(query);
1185 }
1186 
1187 /******************************************************************
1188  *              image_uses_split_segs
1189  *
1190  * Determine if the Mach-O image loaded at a particular address in
1191  * the given process is in the dyld shared cache and therefore has
1192  * its segments mapped non-contiguously.
1193  *
1194  * The image header has to be loaded from the process's memory
1195  * because the relevant flag is only set in memory, not in the file.
1196  */
1197 static BOOL image_uses_split_segs(HANDLE process, unsigned long load_addr)
1198 {
1199     BOOL split_segs = FALSE;
1200 
1201     if (process && load_addr)
1202     {
1203         macho_mach_header header;
1204         if (ReadProcessMemory(process, (void*)load_addr, &header, sizeof(header), NULL) &&
1205             header.magic == TARGET_MH_MAGIC && header.cputype == TARGET_CPU_TYPE &&
1206             header.flags & MACHO_DYLD_IN_SHARED_CACHE)
1207         {
1208             split_segs = TRUE;
1209         }
1210     }
1211 
1212     return split_segs;
1213 }
1214 
1215 /******************************************************************
1216  *              macho_load_debug_info
1217  *
1218  * Loads Mach-O debugging information from the module image file.
1219  */
1220 BOOL macho_load_debug_info(struct module* module)
1221 {
1222     BOOL                    ret = FALSE;
1223     struct macho_debug_info mdi;
1224     int                     result;
1225     struct macho_file_map  *fmap;
1226 
1227     if (module->type != DMT_MACHO || !module->format_info[DFI_MACHO]->u.macho_info)
1228     {
1229         ERR("Bad Mach-O module '%s'\n", debugstr_w(module->module.LoadedImageName));
1230         return FALSE;
1231     }
1232 
1233     fmap = &module->format_info[DFI_MACHO]->u.macho_info->file_map.u.macho;
1234 
1235     TRACE("(%p, %p/%d)\n", module, fmap, fmap->fd);
1236 
1237     module->module.SymType = SymExport;
1238 
1239     if (!(dbghelp_options & SYMOPT_PUBLICS_ONLY))
1240     {
1241         find_and_map_dsym(module);
1242 
1243         if (dwarf2_parse(module, module->reloc_delta, NULL /* FIXME: some thunks to deal with ? */,
1244                          &module->format_info[DFI_MACHO]->u.macho_info->file_map))
1245             ret = TRUE;
1246     }
1247 
1248     mdi.fmap = fmap;
1249     mdi.module = module;
1250     pool_init(&mdi.pool, 65536);
1251     hash_table_init(&mdi.pool, &mdi.ht_symtab, 256);
1252     result = macho_enum_load_commands(fmap, LC_SYMTAB, macho_parse_symtab, &mdi);
1253     if (result > 0)
1254         ret = TRUE;
1255     else if (result < 0)
1256         WARN("Couldn't correctly read stabs\n");
1257 
1258     if (!(dbghelp_options & SYMOPT_PUBLICS_ONLY) && fmap->dsym)
1259     {
1260         mdi.fmap = &fmap->dsym->u.macho;
1261         result = macho_enum_load_commands(mdi.fmap, LC_SYMTAB, macho_parse_symtab, &mdi);
1262         if (result > 0)
1263             ret = TRUE;
1264         else if (result < 0)
1265             WARN("Couldn't correctly read stabs\n");
1266     }
1267 
1268     macho_finish_stabs(module, &mdi.ht_symtab);
1269 
1270     pool_destroy(&mdi.pool);
1271     return ret;
1272 }
1273 
1274 /******************************************************************
1275  *              macho_fetch_file_info
1276  *
1277  * Gathers some more information for a Mach-O module from a given file
1278  */
1279 BOOL macho_fetch_file_info(HANDLE process, const WCHAR* name, unsigned long load_addr, DWORD_PTR* base,
1280                            DWORD* size, DWORD* checksum)
1281 {
1282     struct image_file_map fmap;
1283     BOOL split_segs;
1284 
1285     TRACE("(%s, %p, %p, %p)\n", debugstr_w(name), base, size, checksum);
1286 
1287     split_segs = image_uses_split_segs(process, load_addr);
1288     if (!macho_map_file(name, split_segs, &fmap)) return FALSE;
1289     if (base) *base = fmap.u.macho.segs_start;
1290     *size = fmap.u.macho.segs_size;
1291     *checksum = calc_crc32(fmap.u.macho.fd);
1292     macho_unmap_file(&fmap);
1293     return TRUE;
1294 }
1295 
1296 /******************************************************************
1297  *              macho_module_remove
1298  */
1299 static void macho_module_remove(struct process* pcs, struct module_format* modfmt)
1300 {
1301     macho_unmap_file(&modfmt->u.macho_info->file_map);
1302     HeapFree(GetProcessHeap(), 0, modfmt);
1303 }
1304 
1305 
1306 /******************************************************************
1307  *              get_dyld_image_info_address
1308  */
1309 static ULONG_PTR get_dyld_image_info_address(struct process* pcs)
1310 {
1311     NTSTATUS status;
1312     PROCESS_BASIC_INFORMATION pbi;
1313     ULONG_PTR dyld_image_info_address = 0;
1314 
1315     /* Get address of PEB */
1316     status = NtQueryInformationProcess(pcs->handle, ProcessBasicInformation, &pbi, sizeof(pbi), NULL);
1317     if (status == STATUS_SUCCESS)
1318     {
1319         /* Read dyld image info address from PEB */
1320         if (ReadProcessMemory(pcs->handle, &pbi.PebBaseAddress->Reserved[0],
1321                               &dyld_image_info_address, sizeof(dyld_image_info_address), NULL))
1322         {
1323             TRACE("got dyld_image_info_address 0x%08lx from PEB %p MacDyldImageInfo %p\n",
1324                   (unsigned long)dyld_image_info_address, pbi.PebBaseAddress, &pbi.PebBaseAddress->Reserved);
1325         }
1326     }
1327 
1328 #ifndef __LP64__ /* No reading the symtab with nlist(3) in LP64 */
1329     if (!dyld_image_info_address)
1330     {
1331         static void* dyld_all_image_infos_addr;
1332 
1333         /* Our next best guess is that dyld was loaded at its base address
1334            and we can find the dyld image infos address by looking up its symbol. */
1335         if (!dyld_all_image_infos_addr)
1336         {
1337             struct nlist nl[2];
1338             memset(nl, 0, sizeof(nl));
1339             nl[0].n_un.n_name = (char*)"_dyld_all_image_infos";
1340             if (!nlist("/usr/lib/dyld", nl))
1341                 dyld_all_image_infos_addr = (void*)nl[0].n_value;
1342         }
1343 
1344         if (dyld_all_image_infos_addr)
1345         {
1346             TRACE("got dyld_image_info_address %p from /usr/lib/dyld symbol table\n",
1347                   dyld_all_image_infos_addr);
1348             dyld_image_info_address = (ULONG_PTR)dyld_all_image_infos_addr;
1349         }
1350     }
1351 #endif
1352 
1353     return dyld_image_info_address;
1354 }
1355 
1356 /******************************************************************
1357  *              macho_load_file
1358  *
1359  * Loads the information for Mach-O module stored in 'filename'.
1360  * The module has been loaded at 'load_addr' address.
1361  * returns
1362  *      FALSE if the file cannot be found/opened or if the file doesn't
1363  *              contain symbolic info (or this info cannot be read or parsed)
1364  *      TRUE on success
1365  */
1366 static BOOL macho_load_file(struct process* pcs, const WCHAR* filename,
1367                             unsigned long load_addr, struct macho_info* macho_info)
1368 {
1369     BOOL                    ret = TRUE;
1370     BOOL                    split_segs;
1371     struct image_file_map   fmap;
1372 
1373     TRACE("(%p/%p, %s, 0x%08lx, %p/0x%08x)\n", pcs, pcs->handle, debugstr_w(filename),
1374             load_addr, macho_info, macho_info->flags);
1375 
1376     split_segs = image_uses_split_segs(pcs->handle, load_addr);
1377     if (!macho_map_file(filename, split_segs, &fmap)) return FALSE;
1378 
1379     /* Find the dynamic loader's table of images loaded into the process.
1380      */
1381     if (macho_info->flags & MACHO_INFO_DEBUG_HEADER)
1382     {
1383         macho_info->dbg_hdr_addr = (unsigned long)get_dyld_image_info_address(pcs);
1384         ret = TRUE;
1385     }
1386 
1387     if (macho_info->flags & MACHO_INFO_MODULE)
1388     {
1389         struct macho_module_info *macho_module_info;
1390         struct module_format*   modfmt =
1391             HeapAlloc(GetProcessHeap(), 0, sizeof(struct module_format) + sizeof(struct macho_module_info));
1392         if (!modfmt) goto leave;
1393         if (!load_addr)
1394             load_addr = fmap.u.macho.segs_start;
1395         macho_info->module = module_new(pcs, filename, DMT_MACHO, FALSE, load_addr,
1396                                         fmap.u.macho.segs_size, 0, calc_crc32(fmap.u.macho.fd));
1397         if (!macho_info->module)
1398         {
1399             HeapFree(GetProcessHeap(), 0, modfmt);
1400             goto leave;
1401         }
1402         macho_info->module->reloc_delta = macho_info->module->module.BaseOfImage - fmap.u.macho.segs_start;
1403         macho_module_info = (void*)(modfmt + 1);
1404         macho_info->module->format_info[DFI_MACHO] = modfmt;
1405 
1406         modfmt->module       = macho_info->module;
1407         modfmt->remove       = macho_module_remove;
1408         modfmt->loc_compute  = NULL;
1409         modfmt->u.macho_info = macho_module_info;
1410 
1411         macho_module_info->load_addr = load_addr;
1412 
1413         macho_module_info->file_map = fmap;
1414         reset_file_map(&fmap);
1415         if (dbghelp_options & SYMOPT_DEFERRED_LOADS)
1416             macho_info->module->module.SymType = SymDeferred;
1417         else if (!macho_load_debug_info(macho_info->module))
1418             ret = FALSE;
1419 
1420         macho_info->module->format_info[DFI_MACHO]->u.macho_info->in_use = 1;
1421         macho_info->module->format_info[DFI_MACHO]->u.macho_info->is_loader = 0;
1422         TRACE("module = %p\n", macho_info->module);
1423     }
1424 
1425     if (macho_info->flags & MACHO_INFO_NAME)
1426     {
1427         WCHAR*  ptr;
1428         ptr = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(filename) + 1) * sizeof(WCHAR));
1429         if (ptr)
1430         {
1431             strcpyW(ptr, filename);
1432             macho_info->module_name = ptr;
1433         }
1434         else ret = FALSE;
1435         TRACE("module_name = %p %s\n", macho_info->module_name, debugstr_w(macho_info->module_name));
1436     }
1437 leave:
1438     macho_unmap_file(&fmap);
1439 
1440     TRACE(" => %d\n", ret);
1441     return ret;
1442 }
1443 
1444 /******************************************************************
1445  *              macho_load_file_from_path
1446  * Tries to load a Mach-O file from a set of paths (separated by ':')
1447  */
1448 static BOOL macho_load_file_from_path(struct process* pcs,
1449                                       const WCHAR* filename,
1450                                       unsigned long load_addr,
1451                                       const char* path,
1452                                       struct macho_info* macho_info)
1453 {
1454     BOOL                ret = FALSE;
1455     WCHAR               *s, *t, *fn;
1456     WCHAR*              pathW = NULL;
1457     unsigned            len;
1458 
1459     TRACE("(%p/%p, %s, 0x%08lx, %s, %p)\n", pcs, pcs->handle, debugstr_w(filename), load_addr,
1460             debugstr_a(path), macho_info);
1461 
1462     if (!path) return FALSE;
1463 
1464     len = MultiByteToWideChar(CP_UNIXCP, 0, path, -1, NULL, 0);
1465     pathW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1466     if (!pathW) return FALSE;
1467     MultiByteToWideChar(CP_UNIXCP, 0, path, -1, pathW, len);
1468 
1469     for (s = pathW; s && *s; s = (t) ? (t+1) : NULL)
1470     {
1471         t = strchrW(s, ':');
1472         if (t) *t = '\0';
1473         fn = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(filename) + 1 + lstrlenW(s) + 1) * sizeof(WCHAR));
1474         if (!fn) break;
1475         strcpyW(fn, s);
1476         strcatW(fn, S_SlashW);
1477         strcatW(fn, filename);
1478         ret = macho_load_file(pcs, fn, load_addr, macho_info);
1479         HeapFree(GetProcessHeap(), 0, fn);
1480         if (ret) break;
1481         s = (t) ? (t+1) : NULL;
1482     }
1483 
1484     TRACE(" => %d\n", ret);
1485     HeapFree(GetProcessHeap(), 0, pathW);
1486     return ret;
1487 }
1488 
1489 /******************************************************************
1490  *              macho_load_file_from_dll_path
1491  *
1492  * Tries to load a Mach-O file from the dll path
1493  */
1494 static BOOL macho_load_file_from_dll_path(struct process* pcs,
1495                                           const WCHAR* filename,
1496                                           unsigned long load_addr,
1497                                           struct macho_info* macho_info)
1498 {
1499     BOOL ret = FALSE;
1500     unsigned int index = 0;
1501     const char *path;
1502 
1503     TRACE("(%p/%p, %s, 0x%08lx, %p)\n", pcs, pcs->handle, debugstr_w(filename), load_addr,
1504             macho_info);
1505 
1506     while (!ret && (path = wine_dll_enum_load_path( index++ )))
1507     {
1508         WCHAR *name;
1509         unsigned len;
1510 
1511         len = MultiByteToWideChar(CP_UNIXCP, 0, path, -1, NULL, 0);
1512 
1513         name = HeapAlloc( GetProcessHeap(), 0,
1514                           (len + lstrlenW(filename) + 2) * sizeof(WCHAR) );
1515 
1516         if (!name) break;
1517         MultiByteToWideChar(CP_UNIXCP, 0, path, -1, name, len);
1518         strcatW( name, S_SlashW );
1519         strcatW( name, filename );
1520         ret = macho_load_file(pcs, name, load_addr, macho_info);
1521         HeapFree( GetProcessHeap(), 0, name );
1522     }
1523     TRACE(" => %d\n", ret);
1524     return ret;
1525 }
1526 
1527 /******************************************************************
1528  *              macho_search_and_load_file
1529  *
1530  * Lookup a file in standard Mach-O locations, and if found, load it
1531  */
1532 static BOOL macho_search_and_load_file(struct process* pcs, const WCHAR* filename,
1533                                        unsigned long load_addr,
1534                                        struct macho_info* macho_info)
1535 {
1536     BOOL                ret = FALSE;
1537     struct module*      module;
1538     static const WCHAR  S_libstdcPPW[] = {'l','i','b','s','t','d','c','+','+','\0'};
1539     const WCHAR*        p;
1540 
1541     TRACE("(%p/%p, %s, 0x%08lx, %p)\n", pcs, pcs->handle, debugstr_w(filename), load_addr,
1542             macho_info);
1543 
1544     if (filename == NULL || *filename == '\0') return FALSE;
1545     if ((module = module_is_already_loaded(pcs, filename)))
1546     {
1547         macho_info->module = module;
1548         module->format_info[DFI_MACHO]->u.macho_info->in_use = 1;
1549         return module->module.SymType;
1550     }
1551 
1552     if (strstrW(filename, S_libstdcPPW)) return FALSE; /* We know we can't do it */
1553 
1554     /* If has no directories, try PATH first. */
1555     if (!strchrW(filename, '/'))
1556     {
1557         ret = macho_load_file_from_path(pcs, filename, load_addr,
1558                                       getenv("PATH"), macho_info);
1559     }
1560     /* Try DYLD_LIBRARY_PATH, with just the filename (no directories). */
1561     if (!ret)
1562     {
1563         if ((p = strrchrW(filename, '/'))) p++;
1564         else p = filename;
1565         ret = macho_load_file_from_path(pcs, p, load_addr,
1566                                       getenv("DYLD_LIBRARY_PATH"), macho_info);
1567     }
1568     /* Try the path as given. */
1569     if (!ret)
1570         ret = macho_load_file(pcs, filename, load_addr, macho_info);
1571     /* Try DYLD_FALLBACK_LIBRARY_PATH, with just the filename (no directories). */
1572     if (!ret)
1573     {
1574         const char* fallback = getenv("DYLD_FALLBACK_LIBRARY_PATH");
1575         if (!fallback)
1576             fallback = "/usr/local/lib:/lib:/usr/lib";
1577         ret = macho_load_file_from_path(pcs, p, load_addr, fallback, macho_info);
1578     }
1579     if (!ret && !strchrW(filename, '/'))
1580         ret = macho_load_file_from_dll_path(pcs, filename, load_addr, macho_info);
1581 
1582     return ret;
1583 }
1584 
1585 /******************************************************************
1586  *              macho_enum_modules_internal
1587  *
1588  * Enumerate Mach-O modules from a running process
1589  */
1590 static BOOL macho_enum_modules_internal(const struct process* pcs,
1591                                         const WCHAR* main_name,
1592                                         enum_modules_cb cb, void* user)
1593 {
1594     struct dyld_all_image_infos image_infos;
1595     struct dyld_image_info*     info_array = NULL;
1596     unsigned long               len;
1597     int                         i;
1598     char                        bufstr[256];
1599     WCHAR                       bufstrW[MAX_PATH];
1600     BOOL                        ret = FALSE;
1601 
1602     TRACE("(%p/%p, %s, %p, %p)\n", pcs, pcs->handle, debugstr_w(main_name), cb,
1603             user);
1604 
1605     if (!pcs->dbg_hdr_addr ||
1606         !ReadProcessMemory(pcs->handle, (void*)pcs->dbg_hdr_addr,
1607                            &image_infos, sizeof(image_infos), NULL) ||
1608         !image_infos.infoArray)
1609         goto done;
1610     TRACE("Process has %u image infos at %p\n", image_infos.infoArrayCount, image_infos.infoArray);
1611 
1612     len = image_infos.infoArrayCount * sizeof(info_array[0]);
1613     info_array = HeapAlloc(GetProcessHeap(), 0, len);
1614     if (!info_array ||
1615         !ReadProcessMemory(pcs->handle, image_infos.infoArray,
1616                            info_array, len, NULL))
1617         goto done;
1618     TRACE("... read image infos\n");
1619 
1620     for (i = 0; i < image_infos.infoArrayCount; i++)
1621     {
1622         if (info_array[i].imageFilePath != NULL &&
1623             ReadProcessMemory(pcs->handle, info_array[i].imageFilePath, bufstr, sizeof(bufstr), NULL))
1624         {
1625             bufstr[sizeof(bufstr) - 1] = '\0';
1626             TRACE("[%d] image file %s\n", i, debugstr_a(bufstr));
1627             MultiByteToWideChar(CP_UNIXCP, 0, bufstr, -1, bufstrW, sizeof(bufstrW) / sizeof(WCHAR));
1628             if (main_name && !bufstrW[0]) strcpyW(bufstrW, main_name);
1629             if (!cb(bufstrW, (unsigned long)info_array[i].imageLoadAddress, user)) break;
1630         }
1631     }
1632 
1633     ret = TRUE;
1634 done:
1635     HeapFree(GetProcessHeap(), 0, info_array);
1636     return ret;
1637 }
1638 
1639 struct macho_sync
1640 {
1641     struct process*     pcs;
1642     struct macho_info   macho_info;
1643 };
1644 
1645 static BOOL macho_enum_sync_cb(const WCHAR* name, unsigned long addr, void* user)
1646 {
1647     struct macho_sync*  ms = user;
1648 
1649     TRACE("(%s, 0x%08lx, %p)\n", debugstr_w(name), addr, user);
1650     macho_search_and_load_file(ms->pcs, name, addr, &ms->macho_info);
1651     return TRUE;
1652 }
1653 
1654 /******************************************************************
1655  *              macho_synchronize_module_list
1656  *
1657  * Rescans the debuggee's modules list and synchronizes it with
1658  * the one from 'pcs', ie:
1659  * - if a module is in debuggee and not in pcs, it's loaded into pcs
1660  * - if a module is in pcs and not in debuggee, it's unloaded from pcs
1661  */
1662 BOOL    macho_synchronize_module_list(struct process* pcs)
1663 {
1664     struct module*      module;
1665     struct macho_sync     ms;
1666 
1667     TRACE("(%p/%p)\n", pcs, pcs->handle);
1668 
1669     for (module = pcs->lmodules; module; module = module->next)
1670     {
1671         if (module->type == DMT_MACHO && !module->is_virtual)
1672             module->format_info[DFI_MACHO]->u.macho_info->in_use = 0;
1673     }
1674 
1675     ms.pcs = pcs;
1676     ms.macho_info.flags = MACHO_INFO_MODULE;
1677     if (!macho_enum_modules_internal(pcs, NULL, macho_enum_sync_cb, &ms))
1678         return FALSE;
1679 
1680     module = pcs->lmodules;
1681     while (module)
1682     {
1683         if (module->type == DMT_MACHO && !module->is_virtual &&
1684             !module->format_info[DFI_MACHO]->u.macho_info->in_use &&
1685             !module->format_info[DFI_MACHO]->u.macho_info->is_loader)
1686         {
1687             module_remove(pcs, module);
1688             /* restart all over */
1689             module = pcs->lmodules;
1690         }
1691         else module = module->next;
1692     }
1693     return TRUE;
1694 }
1695 
1696 /******************************************************************
1697  *              macho_search_loader
1698  *
1699  * Lookup in a running Mach-O process the loader, and sets its Mach-O link
1700  * address (for accessing the list of loaded images) in pcs.
1701  * If flags is MACHO_INFO_MODULE, the module for the loader is also
1702  * added as a module into pcs.
1703  */
1704 static BOOL macho_search_loader(struct process* pcs, struct macho_info* macho_info)
1705 {
1706     BOOL ret = FALSE;
1707     ULONG_PTR dyld_image_info_address;
1708     struct dyld_all_image_infos image_infos;
1709     struct dyld_image_info image_info;
1710     uint32_t len;
1711     char path[PATH_MAX];
1712     BOOL got_path = FALSE;
1713 
1714     dyld_image_info_address = get_dyld_image_info_address(pcs);
1715     if (dyld_image_info_address &&
1716         ReadProcessMemory(pcs->handle, (void*)dyld_image_info_address, &image_infos, sizeof(image_infos), NULL) &&
1717         image_infos.infoArray && image_infos.infoArrayCount &&
1718         ReadProcessMemory(pcs->handle, image_infos.infoArray, &image_info, sizeof(image_info), NULL) &&
1719         image_info.imageFilePath)
1720     {
1721         for (len = sizeof(path); len > 0; len /= 2)
1722         {
1723             if (ReadProcessMemory(pcs->handle, image_info.imageFilePath, path, len, NULL))
1724             {
1725                 path[len - 1] = 0;
1726                 got_path = TRUE;
1727                 TRACE("got executable path from target's dyld image info: %s\n", debugstr_a(path));
1728                 break;
1729             }
1730         }
1731     }
1732 
1733     /* If we couldn't get the executable path from the target process, try our
1734        own.  It will almost always be the same. */
1735     if (!got_path)
1736     {
1737         len = sizeof(path);
1738         if (!_NSGetExecutablePath(path, &len))
1739         {
1740             got_path = TRUE;
1741             TRACE("using own executable path: %s\n", debugstr_a(path));
1742         }
1743     }
1744 
1745     if (got_path)
1746     {
1747         WCHAR* pathW;
1748 
1749         len = MultiByteToWideChar(CP_UNIXCP, 0, path, -1, NULL, 0);
1750         pathW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1751         if (pathW)
1752         {
1753             MultiByteToWideChar(CP_UNIXCP, 0, path, -1, pathW, len);
1754             ret = macho_load_file(pcs, pathW, 0, macho_info);
1755             HeapFree(GetProcessHeap(), 0, pathW);
1756         }
1757     }
1758 
1759     if (!ret)
1760         ret = macho_search_and_load_file(pcs, get_wine_loader_name(), 0, macho_info);
1761     return ret;
1762 }
1763 
1764 /******************************************************************
1765  *              macho_read_wine_loader_dbg_info
1766  *
1767  * Try to find a decent wine executable which could have loaded the debuggee
1768  */
1769 BOOL macho_read_wine_loader_dbg_info(struct process* pcs)
1770 {
1771     struct macho_info     macho_info;
1772 
1773     TRACE("(%p/%p)\n", pcs, pcs->handle);
1774     macho_info.flags = MACHO_INFO_DEBUG_HEADER | MACHO_INFO_MODULE;
1775     if (!macho_search_loader(pcs, &macho_info)) return FALSE;
1776     macho_info.module->format_info[DFI_MACHO]->u.macho_info->is_loader = 1;
1777     module_set_module(macho_info.module, S_WineLoaderW);
1778     return (pcs->dbg_hdr_addr = macho_info.dbg_hdr_addr) != 0;
1779 }
1780 
1781 /******************************************************************
1782  *              macho_enum_modules
1783  *
1784  * Enumerates the Mach-O loaded modules from a running target (hProc)
1785  * This function doesn't require that someone has called SymInitialize
1786  * on this very process.
1787  */
1788 BOOL macho_enum_modules(HANDLE hProc, enum_modules_cb cb, void* user)
1789 {
1790     struct process      pcs;
1791     struct macho_info   macho_info;
1792     BOOL                ret;
1793 
1794     TRACE("(%p, %p, %p)\n", hProc, cb, user);
1795     memset(&pcs, 0, sizeof(pcs));
1796     pcs.handle = hProc;
1797     macho_info.flags = MACHO_INFO_DEBUG_HEADER | MACHO_INFO_NAME;
1798     if (!macho_search_loader(&pcs, &macho_info)) return FALSE;
1799     pcs.dbg_hdr_addr = macho_info.dbg_hdr_addr;
1800     ret = macho_enum_modules_internal(&pcs, macho_info.module_name, cb, user);
1801     HeapFree(GetProcessHeap(), 0, (char*)macho_info.module_name);
1802     return ret;
1803 }
1804 
1805 struct macho_load
1806 {
1807     struct process*     pcs;
1808     struct macho_info   macho_info;
1809     const WCHAR*        name;
1810     BOOL                ret;
1811 };
1812 
1813 /******************************************************************
1814  *              macho_load_cb
1815  *
1816  * Callback for macho_load_module, used to walk the list of loaded
1817  * modules.
1818  */
1819 static BOOL macho_load_cb(const WCHAR* name, unsigned long addr, void* user)
1820 {
1821     struct macho_load*  ml = user;
1822     const WCHAR*        p;
1823 
1824     TRACE("(%s, 0x%08lx, %p)\n", debugstr_w(name), addr, user);
1825 
1826     /* memcmp is needed for matches when bufstr contains also version information
1827      * ml->name: libc.so, name: libc.so.6.0
1828      */
1829     p = strrchrW(name, '/');
1830     if (!p++) p = name;
1831     if (!memcmp(p, ml->name, lstrlenW(ml->name) * sizeof(WCHAR)))
1832     {
1833         ml->ret = macho_search_and_load_file(ml->pcs, name, addr, &ml->macho_info);
1834         return FALSE;
1835     }
1836     return TRUE;
1837 }
1838 
1839 /******************************************************************
1840  *              macho_load_module
1841  *
1842  * Loads a Mach-O module and stores it in process' module list.
1843  * Also, find module real name and load address from
1844  * the real loaded modules list in pcs address space.
1845  */
1846 struct module*  macho_load_module(struct process* pcs, const WCHAR* name, unsigned long addr)
1847 {
1848     struct macho_load   ml;
1849 
1850     TRACE("(%p/%p, %s, 0x%08lx)\n", pcs, pcs->handle, debugstr_w(name), addr);
1851 
1852     ml.macho_info.flags = MACHO_INFO_MODULE;
1853     ml.ret = FALSE;
1854 
1855     if (pcs->dbg_hdr_addr) /* we're debugging a live target */
1856     {
1857         ml.pcs = pcs;
1858         /* do only the lookup from the filename, not the path (as we lookup module
1859          * name in the process' loaded module list)
1860          */
1861         ml.name = strrchrW(name, '/');
1862         if (!ml.name++) ml.name = name;
1863         ml.ret = FALSE;
1864 
1865         if (!macho_enum_modules_internal(pcs, NULL, macho_load_cb, &ml))
1866             return NULL;
1867     }
1868     else if (addr)
1869     {
1870         ml.name = name;
1871         ml.ret = macho_search_and_load_file(pcs, ml.name, addr, &ml.macho_info);
1872     }
1873     if (!ml.ret) return NULL;
1874     assert(ml.macho_info.module);
1875     return ml.macho_info.module;
1876 }
1877 
1878 #else  /* HAVE_MACH_O_LOADER_H */
1879 
1880 BOOL macho_find_section(struct image_file_map* ifm, const char* segname, const char* sectname, struct image_section_map* ism)
1881 {
1882     return FALSE;
1883 }
1884 
1885 const char* macho_map_section(struct image_section_map* ism)
1886 {
1887     return NULL;
1888 }
1889 
1890 void macho_unmap_section(struct image_section_map* ism)
1891 {
1892 }
1893 
1894 DWORD_PTR macho_get_map_rva(const struct image_section_map* ism)
1895 {
1896     return 0;
1897 }
1898 
1899 unsigned macho_get_map_size(const struct image_section_map* ism)
1900 {
1901     return 0;
1902 }
1903 
1904 BOOL    macho_synchronize_module_list(struct process* pcs)
1905 {
1906     return FALSE;
1907 }
1908 
1909 BOOL macho_fetch_file_info(HANDLE process, const WCHAR* name, unsigned long load_addr, DWORD_PTR* base,
1910                            DWORD* size, DWORD* checksum)
1911 {
1912     return FALSE;
1913 }
1914 
1915 BOOL macho_read_wine_loader_dbg_info(struct process* pcs)
1916 {
1917     return FALSE;
1918 }
1919 
1920 BOOL macho_enum_modules(HANDLE hProc, enum_modules_cb cb, void* user)
1921 {
1922     return FALSE;
1923 }
1924 
1925 struct module*  macho_load_module(struct process* pcs, const WCHAR* name, unsigned long addr)
1926 {
1927     return NULL;
1928 }
1929 
1930 BOOL macho_load_debug_info(struct module* module)
1931 {
1932     return FALSE;
1933 }
1934 #endif  /* HAVE_MACH_O_LOADER_H */
1935