d3d10core/tests: Add a small test for ID3D10Device_CreateShaderResourceView().
[wine] / dlls / dbghelp / macho_module.c
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 #include "dbghelp_private.h"
28
29 #ifdef HAVE_MACH_O_LOADER_H
30
31 #include <assert.h>
32 #include <stdarg.h>
33 #ifdef HAVE_SYS_STAT_H
34 # include <sys/stat.h>
35 #endif
36 #ifdef HAVE_SYS_MMAN_H
37 # include <sys/mman.h>
38 #endif
39
40 #include <mach-o/fat.h>
41 #include <mach-o/loader.h>
42 #include <mach-o/nlist.h>
43
44 #ifdef HAVE_MACH_O_DYLD_IMAGES_H
45 #include <mach-o/dyld_images.h>
46 #else
47 struct dyld_image_info {
48     const struct mach_header *imageLoadAddress;
49     const char               *imageFilePath;
50     uintptr_t                 imageFileModDate;
51 };
52
53 struct dyld_all_image_infos {
54     uint32_t                      version;
55     uint32_t                      infoArrayCount;
56     const struct dyld_image_info *infoArray;
57     void*                         notification;
58     int                           processDetachedFromSharedRegion;
59 };
60 #endif
61
62 #include "winternl.h"
63 #include "wine/library.h"
64 #include "wine/debug.h"
65
66 #ifdef WORDS_BIGENDIAN
67 #define swap_ulong_be_to_host(n) (n)
68 #else
69 #define swap_ulong_be_to_host(n) (RtlUlongByteSwap(n))
70 #endif
71
72 WINE_DEFAULT_DEBUG_CHANNEL(dbghelp_macho);
73
74
75 struct macho_module_info
76 {
77     unsigned long               load_addr;
78     unsigned short              in_use : 1,
79                                 is_loader : 1;
80 };
81
82 #define MACHO_INFO_DEBUG_HEADER   0x0001
83 #define MACHO_INFO_MODULE         0x0002
84 #define MACHO_INFO_NAME           0x0004
85
86 struct macho_info
87 {
88     unsigned                    flags;          /* IN  one (or several) of the MACHO_INFO constants */
89     unsigned long               dbg_hdr_addr;   /* OUT address of debug header (if MACHO_INFO_DEBUG_HEADER is set) */
90     struct module*              module;         /* OUT loaded module (if MACHO_INFO_MODULE is set) */
91     const WCHAR*                module_name;    /* OUT found module name (if MACHO_INFO_NAME is set) */
92 };
93
94 /* structure holding information while handling a Mach-O image */
95 #define BITS_PER_ULONG (sizeof(ULONG) * 8)
96 #define ULONGS_FOR_BITS(nbits) (((nbits) + BITS_PER_ULONG - 1) / BITS_PER_ULONG)
97 struct macho_file_map
98 {
99     /* A copy of the Mach-O header for an individual architecture. */
100     struct mach_header          mach_header;
101
102     /* The mapped load commands. */
103     const struct load_command*  load_commands;
104
105     /* The portion of the file which is this architecture.  mach_header was
106      * read from arch_offset. */
107     unsigned                    arch_offset;
108     unsigned                    arch_size;
109
110     /* The range of address space covered by all segments. */
111     size_t                      segs_start;
112     size_t                      segs_size;
113
114     /* Map of which sections contain code.  Sections are accessed using 1-based
115      * index.  Bit 0 of this bitset indicates if the bitset has been initialized. */
116     RTL_BITMAP                  sect_is_code;
117     ULONG                       sect_is_code_buff[ULONGS_FOR_BITS(MAX_SECT + 1)];
118
119     /* The file. */
120     int                         fd;
121 };
122
123 static void macho_unmap_file(struct macho_file_map* fmap);
124
125 /******************************************************************
126  *              macho_calc_range
127  *
128  * For a range (offset & length) of a single architecture within
129  * a Mach-O file, calculate the page-aligned range of the whole file
130  * that encompasses it.  For a fat binary, the architecture will
131  * itself be offset within the file, so take that into account.
132  */
133 static void macho_calc_range(const struct macho_file_map* fmap, unsigned offset,
134                              unsigned len, unsigned* out_aligned_offset,
135                              unsigned* out_aligned_end, unsigned* out_aligned_len,
136                              unsigned* out_misalign)
137 {
138     unsigned pagemask = getpagesize() - 1;
139     unsigned file_offset, misalign;
140
141     file_offset = fmap->arch_offset + offset;
142     misalign = file_offset & pagemask;
143     *out_aligned_offset = file_offset - misalign;
144     *out_aligned_end = (file_offset + len + pagemask) & ~pagemask;
145     if (out_aligned_len)
146         *out_aligned_len = *out_aligned_end - *out_aligned_offset;
147     if (out_misalign)
148         *out_misalign = misalign;
149 }
150
151 /******************************************************************
152  *              macho_map_range
153  *
154  * Maps a range (offset, length in bytes) from a Mach-O file into memory
155  */
156 static const char* macho_map_range(const struct macho_file_map* fmap, unsigned offset, unsigned len)
157 {
158     unsigned    misalign, aligned_offset, aligned_map_end, map_size;
159     const void* aligned_ptr;
160
161     TRACE("(%p/%d, 0x%08x, 0x%08x)\n", fmap, fmap->fd, offset, len);
162
163     macho_calc_range(fmap, offset, len, &aligned_offset, &aligned_map_end,
164                      &map_size, &misalign);
165
166     aligned_ptr = mmap(NULL, map_size, PROT_READ, MAP_PRIVATE, fmap->fd, aligned_offset);
167
168     TRACE("Mapped (0x%08x - 0x%08x) to %p\n", aligned_offset, aligned_map_end, aligned_ptr);
169
170     if (aligned_ptr == MAP_FAILED) return MACHO_NO_MAP;
171     return (const char*)aligned_ptr + misalign;
172 }
173
174 /******************************************************************
175  *              macho_unmap_range
176  *
177  * Unmaps a range (offset, length in bytes) of a Mach-O file from memory
178  */
179 static void macho_unmap_range(const void** mapped, const struct macho_file_map* fmap,
180                               unsigned offset, unsigned len)
181 {
182     TRACE("(%p, %p/%d, 0x%08x, 0x%08x)\n", mapped, fmap, fmap->fd, offset, len);
183
184     if (mapped && *mapped != MACHO_NO_MAP)
185     {
186         unsigned    misalign, aligned_offset, aligned_map_end, map_size;
187         void*       aligned_ptr;
188
189         macho_calc_range(fmap, offset, len, &aligned_offset, &aligned_map_end,
190                          &map_size, &misalign);
191
192         aligned_ptr = (char*)*mapped - misalign;
193         if (munmap(aligned_ptr, map_size) < 0)
194             WARN("Couldn't unmap the range\n");
195         TRACE("Unmapped (0x%08x - 0x%08x) from %p - %p\n", aligned_offset, aligned_map_end, aligned_ptr, (char*)aligned_ptr + map_size);
196         *mapped = MACHO_NO_MAP;
197     }
198 }
199
200 /******************************************************************
201  *              macho_map_ranges
202  *
203  * Maps two ranges (offset, length in bytes) from a Mach-O file
204  * into memory.  If the two ranges overlap, use one mmap so that
205  * the munmap doesn't fragment the mapping.
206  */
207 static BOOL macho_map_ranges(const struct macho_file_map* fmap,
208                              unsigned offset1, unsigned len1,
209                              unsigned offset2, unsigned len2,
210                              const void** mapped1, const void** mapped2)
211 {
212     unsigned aligned_offset1, aligned_map_end1;
213     unsigned aligned_offset2, aligned_map_end2;
214
215     TRACE("(%p/%d, 0x%08x, 0x%08x, 0x%08x, 0x%08x, %p, %p)\n", fmap, fmap->fd,
216             offset1, len1, offset2, len2, mapped1, mapped2);
217
218     macho_calc_range(fmap, offset1, len1, &aligned_offset1, &aligned_map_end1, NULL, NULL);
219     macho_calc_range(fmap, offset2, len2, &aligned_offset2, &aligned_map_end2, NULL, NULL);
220
221     if (aligned_map_end1 < aligned_offset2 || aligned_map_end2 < aligned_offset1)
222     {
223         *mapped1 = macho_map_range(fmap, offset1, len1);
224         if (*mapped1 != MACHO_NO_MAP)
225         {
226             *mapped2 = macho_map_range(fmap, offset2, len2);
227             if (*mapped2 == MACHO_NO_MAP)
228                 macho_unmap_range(mapped1, fmap, offset1, len1);
229         }
230     }
231     else
232     {
233         if (offset1 < offset2)
234         {
235             *mapped1 = macho_map_range(fmap, offset1, offset2 + len2 - offset1);
236             if (*mapped1 != MACHO_NO_MAP)
237                 *mapped2 = (const char*)*mapped1 + offset2 - offset1;
238         }
239         else
240         {
241             *mapped2 = macho_map_range(fmap, offset2, offset1 + len1 - offset2);
242             if (*mapped2 != MACHO_NO_MAP)
243                 *mapped1 = (const char*)*mapped2 + offset1 - offset2;
244         }
245     }
246
247     TRACE(" => %p, %p\n", *mapped1, *mapped2);
248
249     return (*mapped1 != MACHO_NO_MAP) && (*mapped2 != MACHO_NO_MAP);
250 }
251
252 /******************************************************************
253  *              macho_unmap_ranges
254  *
255  * Unmaps two ranges (offset, length in bytes) of a Mach-O file
256  * from memory.  Use for ranges which were mapped by
257  * macho_map_ranges.
258  */
259 static void macho_unmap_ranges(const struct macho_file_map* fmap,
260                                unsigned offset1, unsigned len1,
261                                unsigned offset2, unsigned len2,
262                                const void** mapped1, const void** mapped2)
263 {
264     unsigned    aligned_offset1, aligned_map_end1;
265     unsigned    aligned_offset2, aligned_map_end2;
266
267     TRACE("(%p/%d, 0x%08x, 0x%08x, 0x%08x, 0x%08x, %p/%p, %p/%p)\n", fmap, fmap->fd,
268             offset1, len1, offset2, len2, mapped1, *mapped1, mapped2, *mapped2);
269
270     macho_calc_range(fmap, offset1, len1, &aligned_offset1, &aligned_map_end1, NULL, NULL);
271     macho_calc_range(fmap, offset2, len2, &aligned_offset2, &aligned_map_end2, NULL, NULL);
272
273     if (aligned_map_end1 < aligned_offset2 || aligned_map_end2 < aligned_offset1)
274     {
275         macho_unmap_range(mapped1, fmap, offset1, len1);
276         macho_unmap_range(mapped2, fmap, offset2, len2);
277     }
278     else
279     {
280         if (offset1 < offset2)
281         {
282             macho_unmap_range(mapped1, fmap, offset1, offset2 + len2 - offset1);
283             *mapped2 = MACHO_NO_MAP;
284         }
285         else
286         {
287             macho_unmap_range(mapped2, fmap, offset2, offset1 + len1 - offset2);
288             *mapped1 = MACHO_NO_MAP;
289         }
290     }
291 }
292
293 /******************************************************************
294  *              macho_map_load_commands
295  *
296  * Maps the load commands from a Mach-O file into memory
297  */
298 static const struct load_command* macho_map_load_commands(struct macho_file_map* fmap)
299 {
300     if (fmap->load_commands == MACHO_NO_MAP)
301     {
302         fmap->load_commands = (const struct load_command*) macho_map_range(
303                 fmap, sizeof(fmap->mach_header), fmap->mach_header.sizeofcmds);
304         TRACE("Mapped load commands: %p\n", fmap->load_commands);
305     }
306
307     return fmap->load_commands;
308 }
309
310 /******************************************************************
311  *              macho_unmap_load_commands
312  *
313  * Unmaps the load commands of a Mach-O file from memory
314  */
315 static void macho_unmap_load_commands(struct macho_file_map* fmap)
316 {
317     if (fmap->load_commands != MACHO_NO_MAP)
318     {
319         TRACE("Unmapping load commands: %p\n", fmap->load_commands);
320         macho_unmap_range((const void**)&fmap->load_commands, fmap,
321                     sizeof(fmap->mach_header), fmap->mach_header.sizeofcmds);
322     }
323 }
324
325 /******************************************************************
326  *              macho_next_load_command
327  *
328  * Advance to the next load command
329  */
330 static const struct load_command* macho_next_load_command(const struct load_command* lc)
331 {
332     return (const struct load_command*)((const char*)lc + lc->cmdsize);
333 }
334
335 /******************************************************************
336  *              macho_enum_load_commands
337  *
338  * Enumerates the load commands for a Mach-O file, selecting by
339  * the command type, calling a callback for each.  If the callback
340  * returns <0, that indicates an error.  If it returns >0, that means
341  * it's not interested in getting any more load commands.
342  * If this function returns <0, that's an error produced by the
343  * callback.  If >=0, that's the count of load commands successfully
344  * processed.
345  */
346 static int macho_enum_load_commands(struct macho_file_map* fmap, unsigned cmd,
347                                     int (*cb)(struct macho_file_map*, const struct load_command*, void*),
348                                     void* user)
349 {
350     const struct load_command* lc;
351     int i;
352     int count = 0;
353
354     TRACE("(%p/%d, %u, %p, %p)\n", fmap, fmap->fd, cmd, cb, user);
355
356     if ((lc = macho_map_load_commands(fmap)) == MACHO_NO_MAP) return -1;
357
358     TRACE("%d total commands\n", fmap->mach_header.ncmds);
359
360     for (i = 0; i < fmap->mach_header.ncmds; i++, lc = macho_next_load_command(lc))
361     {
362         int result;
363
364         if (cmd && cmd != lc->cmd) continue;
365         count++;
366
367         result = cb(fmap, lc, user);
368         TRACE("load_command[%d] (%p), cmd %u; callback => %d\n", i, lc, lc->cmd, result);
369         if (result) return (result < 0) ? result : count;
370     }
371
372     return count;
373 }
374
375 /******************************************************************
376  *              macho_accum_segs_range
377  *
378  * Callback for macho_enum_load_commands.  Accumulates the address
379  * range covered by the segments of a Mach-O file.  All commands
380  * are expected to be of LC_SEGMENT type.
381  */
382 static int macho_accum_segs_range(struct macho_file_map* fmap,
383                                   const struct load_command* lc, void* user)
384 {
385     const struct segment_command*   sc = (const struct segment_command*)lc;
386     unsigned                        tmp, page_mask = getpagesize() - 1;
387
388     TRACE("(%p/%d, %p, %p) before: 0x%08x - 0x%08x\n", fmap, fmap->fd, lc, user,
389             (unsigned)fmap->segs_start, (unsigned)fmap->segs_size);
390     TRACE("Segment command vm: 0x%08x - 0x%08x\n", (unsigned)sc->vmaddr,
391             (unsigned)sc->vmaddr + sc->vmsize);
392
393     if (!strncmp(sc->segname, "WINE_", 5))
394     {
395         TRACE("Ignoring special Wine segment %s\n", debugstr_an(sc->segname, sizeof(sc->segname)));
396         return 0;
397     }
398
399     /* If this segment starts before previously-known earliest, record
400      * new earliest. */
401     if (sc->vmaddr < fmap->segs_start)
402         fmap->segs_start = sc->vmaddr;
403
404     /* If this segment extends beyond previously-known furthest, record
405      * new furthest. */
406     tmp = (sc->vmaddr + sc->vmsize + page_mask) & ~page_mask;
407     if (fmap->segs_size < tmp) fmap->segs_size = tmp;
408
409     TRACE("after: 0x%08x - 0x%08x\n", (unsigned)fmap->segs_start, (unsigned)fmap->segs_size);
410
411     return 0;
412 }
413
414 /******************************************************************
415  *              macho_map_file
416  *
417  * Maps a Mach-O file into memory (and checks it's a real Mach-O file)
418  */
419 static BOOL macho_map_file(const WCHAR* filenameW, struct macho_file_map* fmap)
420 {
421     struct fat_header   fat_header;
422     struct stat         statbuf;
423     int                 i;
424     char*               filename;
425     unsigned            len;
426     BOOL                ret = FALSE;
427
428     TRACE("(%s, %p)\n", debugstr_w(filenameW), fmap);
429
430     fmap->fd = -1;
431     fmap->load_commands = MACHO_NO_MAP;
432     RtlInitializeBitMap(&fmap->sect_is_code, fmap->sect_is_code_buff, MAX_SECT + 1);
433
434     len = WideCharToMultiByte(CP_UNIXCP, 0, filenameW, -1, NULL, 0, NULL, NULL);
435     if (!(filename = HeapAlloc(GetProcessHeap(), 0, len))) return FALSE;
436     WideCharToMultiByte(CP_UNIXCP, 0, filenameW, -1, filename, len, NULL, NULL);
437
438     /* check that the file exists */
439     if (stat(filename, &statbuf) == -1 || S_ISDIR(statbuf.st_mode)) goto done;
440
441     /* Now open the file, so that we can mmap() it. */
442     if ((fmap->fd = open(filename, O_RDONLY)) == -1) goto done;
443
444     if (read(fmap->fd, &fat_header, sizeof(fat_header)) != sizeof(fat_header))
445         goto done;
446     TRACE("... got possible fat header\n");
447
448     /* Fat header is always in big-endian order. */
449     if (swap_ulong_be_to_host(fat_header.magic) == FAT_MAGIC)
450     {
451         int narch = swap_ulong_be_to_host(fat_header.nfat_arch);
452         for (i = 0; i < narch; i++)
453         {
454             struct fat_arch fat_arch;
455             if (read(fmap->fd, &fat_arch, sizeof(fat_arch)) != sizeof(fat_arch))
456                 goto done;
457             if (swap_ulong_be_to_host(fat_arch.cputype) == CPU_TYPE_X86)
458             {
459                 fmap->arch_offset = swap_ulong_be_to_host(fat_arch.offset);
460                 fmap->arch_size = swap_ulong_be_to_host(fat_arch.size);
461                 break;
462             }
463         }
464         if (i >= narch) goto done;
465         TRACE("... found x86 arch\n");
466     }
467     else
468     {
469         fmap->arch_offset = 0;
470         fmap->arch_size = statbuf.st_size;
471         TRACE("... not a fat header\n");
472     }
473
474     /* Individual architecture (standalone or within a fat file) is in its native byte order. */
475     lseek(fmap->fd, fmap->arch_offset, SEEK_SET);
476     if (read(fmap->fd, &fmap->mach_header, sizeof(fmap->mach_header)) != sizeof(fmap->mach_header))
477         goto done;
478     TRACE("... got possible Mach header\n");
479     /* and check for a Mach-O header */
480     if (fmap->mach_header.magic != MH_MAGIC ||
481         fmap->mach_header.cputype != CPU_TYPE_X86) goto done;
482     /* Make sure the file type is one of the ones we expect. */
483     switch (fmap->mach_header.filetype)
484     {
485         case MH_EXECUTE:
486         case MH_DYLIB:
487         case MH_DYLINKER:
488         case MH_BUNDLE:
489             break;
490         default:
491             goto done;
492     }
493     TRACE("... verified Mach x86 header\n");
494
495     fmap->segs_size = 0;
496     fmap->segs_start = ~0L;
497
498     if (macho_enum_load_commands(fmap, LC_SEGMENT, macho_accum_segs_range, NULL) < 0)
499         goto done;
500
501     fmap->segs_size -= fmap->segs_start;
502     TRACE("segs_start: 0x%08x, segs_size: 0x%08x\n", (unsigned)fmap->segs_start,
503             (unsigned)fmap->segs_size);
504
505     ret = TRUE;
506 done:
507     if (!ret)
508         macho_unmap_file(fmap);
509     HeapFree(GetProcessHeap(), 0, filename);
510     return ret;
511 }
512
513 /******************************************************************
514  *              macho_unmap_file
515  *
516  * Unmaps a Mach-O file from memory (previously mapped with macho_map_file)
517  */
518 static void macho_unmap_file(struct macho_file_map* fmap)
519 {
520     TRACE("(%p/%d)\n", fmap, fmap->fd);
521     if (fmap->fd != -1)
522     {
523         macho_unmap_load_commands(fmap);
524         close(fmap->fd);
525         fmap->fd = -1;
526     }
527 }
528
529 /******************************************************************
530  *              macho_fill_sect_is_code
531  *
532  * Callback for macho_enum_load_commands.  Determines which segments
533  * of a Mach-O file contain code.  All commands are expected to be
534  * of LC_SEGMENT type.
535  */
536 static int macho_fill_sect_is_code(struct macho_file_map* fmap,
537                                    const struct load_command* lc, void* user)
538 {
539     const struct segment_command*   sc = (const struct segment_command*)lc;
540     const struct section*           sections;
541     int*                            cursect = user;
542     int                             i;
543
544     TRACE("(%p/%d, %p, %p/%d) scanning %u sections\n", fmap, fmap->fd, lc,
545             cursect, *cursect, sc->nsects);
546
547     sections = (const struct section*)(sc + 1);
548     for (i = 0; i < sc->nsects; i++)
549     {
550         if (*cursect > MAX_SECT) return -1;
551         (*cursect)++;
552
553         if (!(sections[i].flags & SECTION_TYPE) &&
554             (sections[i].flags & (S_ATTR_PURE_INSTRUCTIONS|S_ATTR_SOME_INSTRUCTIONS)))
555             RtlSetBits(&fmap->sect_is_code, *cursect, 1);
556         else
557             RtlClearBits(&fmap->sect_is_code, *cursect, 1);
558         TRACE("Section %d (%d of this segment) is%s code\n", *cursect, i,
559                 (RtlAreBitsSet(&fmap->sect_is_code, *cursect, 1) ? "" : " not"));
560     }
561
562     return 0;
563 }
564
565 /******************************************************************
566  *              macho_sect_is_code
567  *
568  * Checks if a section, identified by sectidx which is a 1-based
569  * index into the sections of all segments, in order of load
570  * commands, contains code.
571  */
572 static BOOL macho_sect_is_code(struct macho_file_map* fmap, unsigned char sectidx)
573 {
574     TRACE("(%p/%d, %u)\n", fmap, fmap->fd, sectidx);
575
576     if (!RtlAreBitsSet(&fmap->sect_is_code, 0, 1))
577     {
578         int cursect = 0;
579         if (macho_enum_load_commands(fmap, LC_SEGMENT, macho_fill_sect_is_code, &cursect) < 0)
580             WARN("Couldn't load sect_is_code map\n");
581         RtlSetBits(&fmap->sect_is_code, 0, 1);
582     }
583
584     return RtlAreBitsSet(&fmap->sect_is_code, sectidx, 1);
585 }
586
587 struct symtab_elt
588 {
589     struct hash_table_elt       ht_elt;
590     struct symt_compiland*      compiland;
591     unsigned long               addr;
592     unsigned char               is_code:1,
593                                 is_public:1,
594                                 is_global:1,
595                                 used:1;
596 };
597
598 struct macho_debug_info
599 {
600     struct macho_file_map*      fmap;
601     struct module*              module;
602     struct pool                 pool;
603     struct hash_table           ht_symtab;
604 };
605
606 /******************************************************************
607  *              macho_stabs_def_cb
608  *
609  * Callback for stabs_parse.  Collect symbol definitions.
610  */
611 static void macho_stabs_def_cb(struct module* module, unsigned long load_offset,
612                                const char* name, unsigned long offset,
613                                BOOL is_public, BOOL is_global, unsigned char sectidx,
614                                struct symt_compiland* compiland, void* user)
615 {
616     struct macho_debug_info*    mdi = user;
617     struct symtab_elt*          ste;
618
619     TRACE("(%p, 0x%08lx, %s, 0x%08lx, %d, %d, %u, %p, %p/%p/%d)\n", module, load_offset,
620             debugstr_a(name), offset, is_public, is_global, sectidx,
621             compiland, mdi, mdi->fmap, mdi->fmap->fd);
622
623     /* Defer the creation of new non-debugging symbols until after we've
624      * finished parsing the stabs. */
625     ste                 = pool_alloc(&mdi->pool, sizeof(*ste));
626     ste->ht_elt.name    = pool_strdup(&mdi->pool, name);
627     ste->compiland      = compiland;
628     ste->addr           = load_offset + offset;
629     ste->is_code        = !!macho_sect_is_code(mdi->fmap, sectidx);
630     ste->is_public      = !!is_public;
631     ste->is_global      = !!is_global;
632     ste->used           = 0;
633     hash_table_add(&mdi->ht_symtab, &ste->ht_elt);
634 }
635
636 /******************************************************************
637  *              macho_parse_symtab
638  *
639  * Callback for macho_enum_load_commands.  Processes the LC_SYMTAB
640  * load commands from the Mach-O file.
641  */
642 static int macho_parse_symtab(struct macho_file_map* fmap,
643                               const struct load_command* lc, void* user)
644 {
645     const struct symtab_command*    sc = (const struct symtab_command*)lc;
646     struct macho_debug_info*        mdi = user;
647     const struct nlist*             stab;
648     const char*                     stabstr;
649     int                             ret = 0;
650
651     TRACE("(%p/%d, %p, %p) %u syms at 0x%08x, strings 0x%08x - 0x%08x\n", fmap, fmap->fd, lc,
652             user, sc->nsyms, sc->symoff, sc->stroff, sc->stroff + sc->strsize);
653
654     if (!macho_map_ranges(fmap, sc->symoff, sc->nsyms * sizeof(struct nlist),
655             sc->stroff, sc->strsize, (const void**)&stab, (const void**)&stabstr))
656         return 0;
657
658     if (!stabs_parse(mdi->module,
659                      mdi->module->format_info[DFI_MACHO]->u.macho_info->load_addr - fmap->segs_start,
660                      stab, sc->nsyms * sizeof(struct nlist),
661                      stabstr, sc->strsize, macho_stabs_def_cb, mdi))
662         ret = -1;
663
664     macho_unmap_ranges(fmap, sc->symoff, sc->nsyms * sizeof(struct nlist),
665             sc->stroff, sc->strsize, (const void**)&stab, (const void**)&stabstr);
666
667     return ret;
668 }
669
670 /******************************************************************
671  *              macho_finish_stabs
672  *
673  * Integrate the non-debugging symbols we've gathered into the
674  * symbols that were generated during stabs parsing.
675  */
676 static void macho_finish_stabs(struct module* module, struct hash_table* ht_symtab)
677 {
678     struct hash_table_iter      hti_ours;
679     struct symtab_elt*          ste;
680     BOOL                        adjusted = FALSE;
681
682     TRACE("(%p, %p)\n", module, ht_symtab);
683
684     /* For each of our non-debugging symbols, see if it can provide some
685      * missing details to one of the module's known symbols. */
686     hash_table_iter_init(ht_symtab, &hti_ours, NULL);
687     while ((ste = hash_table_iter_up(&hti_ours)))
688     {
689         struct hash_table_iter  hti_modules;
690         void*                   ptr;
691         struct symt_ht*         sym;
692         struct symt_function*   func;
693         struct symt_data*       data;
694
695         hash_table_iter_init(&module->ht_symbols, &hti_modules, ste->ht_elt.name);
696         while ((ptr = hash_table_iter_up(&hti_modules)))
697         {
698             sym = GET_ENTRY(ptr, struct symt_ht, hash_elt);
699
700             if (strcmp(sym->hash_elt.name, ste->ht_elt.name))
701                 continue;
702
703             switch (sym->symt.tag)
704             {
705             case SymTagFunction:
706                 func = (struct symt_function*)sym;
707                 if (func->address == module->format_info[DFI_MACHO]->u.macho_info->load_addr)
708                 {
709                     TRACE("Adjusting function %p/%s!%s from 0x%08lx to 0x%08lx\n", func,
710                           debugstr_w(module->module.ModuleName), sym->hash_elt.name,
711                           func->address, ste->addr);
712                     func->address = ste->addr;
713                     adjusted = TRUE;
714                 }
715                 if (func->address == ste->addr)
716                     ste->used = 1;
717                 break;
718             case SymTagData:
719                 data = (struct symt_data*)sym;
720                 switch (data->kind)
721                 {
722                 case DataIsGlobal:
723                 case DataIsFileStatic:
724                     if (data->u.var.offset == module->format_info[DFI_MACHO]->u.macho_info->load_addr)
725                     {
726                         TRACE("Adjusting data symbol %p/%s!%s from 0x%08lx to 0x%08lx\n",
727                               data, debugstr_w(module->module.ModuleName), sym->hash_elt.name,
728                               data->u.var.offset, ste->addr);
729                         data->u.var.offset = ste->addr;
730                         adjusted = TRUE;
731                     }
732                     if (data->u.var.offset == ste->addr)
733                     {
734                         enum DataKind new_kind;
735
736                         new_kind = ste->is_global ? DataIsGlobal : DataIsFileStatic;
737                         if (data->kind != new_kind)
738                         {
739                             WARN("Changing kind for %p/%s!%s from %d to %d\n", sym,
740                                  debugstr_w(module->module.ModuleName), sym->hash_elt.name,
741                                  (int)data->kind, (int)new_kind);
742                             data->kind = new_kind;
743                             adjusted = TRUE;
744                         }
745                         ste->used = 1;
746                     }
747                     break;
748                 default:;
749                 }
750                 break;
751             default:
752                 TRACE("Ignoring tag %u\n", sym->symt.tag);
753                 break;
754             }
755         }
756     }
757
758     if (adjusted)
759     {
760         /* since we may have changed some addresses, mark the module to be resorted */
761         module->sortlist_valid = FALSE;
762     }
763
764     /* Mark any of our non-debugging symbols which fall on an already-used
765      * address as "used".  This allows us to skip them in the next loop,
766      * below.  We do this in separate loops because symt_new_* marks the
767      * list as needing sorting and symt_find_nearest sorts if needed,
768      * causing thrashing. */
769     if (!(dbghelp_options & SYMOPT_PUBLICS_ONLY))
770     {
771         hash_table_iter_init(ht_symtab, &hti_ours, NULL);
772         while ((ste = hash_table_iter_up(&hti_ours)))
773         {
774             struct symt_ht* sym;
775             ULONG64         addr;
776
777             if (ste->used) continue;
778
779             sym = symt_find_nearest(module, ste->addr);
780             if (sym)
781                 symt_get_address(&sym->symt, &addr);
782             if (sym && ste->addr == addr)
783             {
784                 ULONG64 size = 0;
785                 DWORD   kind = -1;
786
787                 ste->used = 1;
788
789                 /* If neither symbol has a correct size (ours never does), we
790                  * consider them both to be markers.  No warning is needed in
791                  * that case.
792                  * Also, we check that we don't have two symbols, one local, the other
793                  * global, which is legal.
794                  */
795                 symt_get_info(module, &sym->symt, TI_GET_LENGTH,   &size);
796                 symt_get_info(module, &sym->symt, TI_GET_DATAKIND, &kind);
797                 if (size && kind == (ste->is_global ? DataIsGlobal : DataIsFileStatic))
798                     FIXME("Duplicate in %s: %s<%08lx> %s<%s-%s>\n",
799                           debugstr_w(module->module.ModuleName),
800                           ste->ht_elt.name, ste->addr,
801                           sym->hash_elt.name,
802                           wine_dbgstr_longlong(addr), wine_dbgstr_longlong(size));
803             }
804         }
805     }
806
807     /* For any of our remaining non-debugging symbols which have no match
808      * among the module's known symbols, add them as new symbols. */
809     hash_table_iter_init(ht_symtab, &hti_ours, NULL);
810     while ((ste = hash_table_iter_up(&hti_ours)))
811     {
812         if (!(dbghelp_options & SYMOPT_PUBLICS_ONLY) && !ste->used)
813         {
814             if (ste->is_code)
815             {
816                 symt_new_function(module, ste->compiland, ste->ht_elt.name,
817                     ste->addr, 0, NULL);
818             }
819             else
820             {
821                 struct location loc;
822
823                 loc.kind = loc_absolute;
824                 loc.reg = 0;
825                 loc.offset = ste->addr;
826                 symt_new_global_variable(module, ste->compiland, ste->ht_elt.name,
827                                          !ste->is_global, loc, 0, NULL);
828             }
829
830             ste->used = 1;
831         }
832
833         if (ste->is_public && !(dbghelp_options & SYMOPT_NO_PUBLICS))
834         {
835             symt_new_public(module, ste->compiland, ste->ht_elt.name, ste->addr, 0);
836         }
837     }
838 }
839
840 /******************************************************************
841  *              macho_load_debug_info_from_map
842  *
843  * Loads the symbolic information from a Mach-O module.
844  * Returns
845  *      FALSE if the file doesn't contain symbolic info (or this info
846  *              cannot be read or parsed)
847  *      TRUE on success
848  */
849 static BOOL macho_load_debug_info_from_map(struct module* module,
850                                            struct macho_file_map* fmap)
851 {
852     BOOL                    ret = FALSE;
853     struct macho_debug_info mdi;
854     int                     result;
855
856     TRACE("(%p, %p/%d)\n", module, fmap, fmap->fd);
857
858     module->module.SymType = SymExport;
859
860     mdi.fmap = fmap;
861     mdi.module = module;
862     pool_init(&mdi.pool, 65536);
863     hash_table_init(&mdi.pool, &mdi.ht_symtab, 256);
864     result = macho_enum_load_commands(fmap, LC_SYMTAB, macho_parse_symtab, &mdi);
865     if (result > 0)
866         ret = TRUE;
867     else if (result < 0)
868         WARN("Couldn't correctly read stabs\n");
869
870     macho_finish_stabs(module, &mdi.ht_symtab);
871
872     pool_destroy(&mdi.pool);
873     return ret;
874 }
875
876 /******************************************************************
877  *              macho_load_debug_info
878  *
879  * Loads Mach-O debugging information from the module image file.
880  */
881 BOOL macho_load_debug_info(struct module* module, struct macho_file_map* fmap)
882 {
883     BOOL                    ret = TRUE;
884     struct macho_file_map   my_fmap;
885
886     TRACE("(%p, %p/%d)\n", module, fmap, fmap ? fmap->fd : -1);
887
888     if (module->type != DMT_MACHO || !module->format_info[DFI_MACHO]->u.macho_info)
889     {
890         ERR("Bad Mach-O module '%s'\n", debugstr_w(module->module.LoadedImageName));
891         return FALSE;
892     }
893
894     if (!fmap)
895     {
896         fmap = &my_fmap;
897         ret = macho_map_file(module->module.LoadedImageName, fmap);
898     }
899     if (ret)
900         ret = macho_load_debug_info_from_map(module, fmap);
901
902     if (fmap == &my_fmap) macho_unmap_file(fmap);
903     return ret;
904 }
905
906 /******************************************************************
907  *              macho_fetch_file_info
908  *
909  * Gathers some more information for a Mach-O module from a given file
910  */
911 BOOL macho_fetch_file_info(const WCHAR* name, DWORD_PTR* base,
912                            DWORD* size, DWORD* checksum)
913 {
914     struct macho_file_map fmap;
915
916     TRACE("(%s, %p, %p, %p)\n", debugstr_w(name), base, size, checksum);
917
918     if (!macho_map_file(name, &fmap)) return FALSE;
919     if (base) *base = fmap.segs_start;
920     *size = fmap.segs_size;
921     *checksum = calc_crc32(fmap.fd);
922     macho_unmap_file(&fmap);
923     return TRUE;
924 }
925
926 /******************************************************************
927  *              macho_load_file
928  *
929  * Loads the information for Mach-O module stored in 'filename'.
930  * The module has been loaded at 'load_addr' address.
931  * returns
932  *      FALSE if the file cannot be found/opened or if the file doesn't
933  *              contain symbolic info (or this info cannot be read or parsed)
934  *      TRUE on success
935  */
936 static BOOL macho_load_file(struct process* pcs, const WCHAR* filename,
937                             unsigned long load_addr, struct macho_info* macho_info)
938 {
939     BOOL                    ret = TRUE;
940     struct macho_file_map   fmap;
941
942     TRACE("(%p/%p, %s, 0x%08lx, %p/0x%08x)\n", pcs, pcs->handle, debugstr_w(filename),
943             load_addr, macho_info, macho_info->flags);
944
945     if (!macho_map_file(filename, &fmap)) return FALSE;
946
947     /* Find the dynamic loader's table of images loaded into the process.
948      */
949     if (macho_info->flags & MACHO_INFO_DEBUG_HEADER)
950     {
951         static void* dyld_all_image_infos_addr;
952
953         /* This symbol should be in the same place in all processes. */
954         if (!dyld_all_image_infos_addr)
955         {
956             struct nlist nl[2];
957             memset(nl, 0, sizeof(nl));
958             nl[0].n_un.n_name = (char*)"_dyld_all_image_infos";
959             if (!nlist("/usr/lib/dyld", nl))
960                 dyld_all_image_infos_addr = (void*)nl[0].n_value;
961         }
962
963         if (dyld_all_image_infos_addr)
964             macho_info->dbg_hdr_addr = (unsigned long)dyld_all_image_infos_addr;
965         else
966             ret = FALSE;
967         TRACE("dbg_hdr_addr = 0x%08lx\n", macho_info->dbg_hdr_addr);
968     }
969
970     if (macho_info->flags & MACHO_INFO_MODULE)
971     {
972         struct macho_module_info *macho_module_info;
973         struct module_format*   modfmt =
974             HeapAlloc(GetProcessHeap(), 0, sizeof(struct module_format) + sizeof(struct macho_module_info));
975         if (!modfmt) goto leave;
976         macho_info->module = module_new(pcs, filename, DMT_MACHO, FALSE, load_addr,
977                                         fmap.segs_size, 0, calc_crc32(fmap.fd));
978         if (!macho_info->module)
979         {
980             HeapFree(GetProcessHeap(), 0, modfmt);
981             goto leave;
982         }
983         macho_module_info = (void*)(modfmt + 1);
984         macho_info->module->format_info[DFI_MACHO] = modfmt;
985
986         modfmt->module       = macho_info->module;
987         modfmt->remove       = NULL;
988         modfmt->loc_compute  = NULL;
989         modfmt->u.macho_info = macho_module_info;
990
991         macho_module_info->load_addr = load_addr;
992
993         if (dbghelp_options & SYMOPT_DEFERRED_LOADS)
994             macho_info->module->module.SymType = SymDeferred;
995         else if (!macho_load_debug_info(macho_info->module, &fmap))
996             ret = FALSE;
997
998         macho_info->module->format_info[DFI_MACHO]->u.macho_info->in_use = 1;
999         macho_info->module->format_info[DFI_MACHO]->u.macho_info->is_loader = 0;
1000         TRACE("module = %p\n", macho_info->module);
1001     }
1002
1003     if (macho_info->flags & MACHO_INFO_NAME)
1004     {
1005         WCHAR*  ptr;
1006         ptr = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(filename) + 1) * sizeof(WCHAR));
1007         if (ptr)
1008         {
1009             strcpyW(ptr, filename);
1010             macho_info->module_name = ptr;
1011         }
1012         else ret = FALSE;
1013         TRACE("module_name = %p %s\n", macho_info->module_name, debugstr_w(macho_info->module_name));
1014     }
1015 leave:
1016     macho_unmap_file(&fmap);
1017
1018     TRACE(" => %d\n", ret);
1019     return ret;
1020 }
1021
1022 /******************************************************************
1023  *              macho_load_file_from_path
1024  * Tries to load a Mach-O file from a set of paths (separated by ':')
1025  */
1026 static BOOL macho_load_file_from_path(HANDLE hProcess,
1027                                       const WCHAR* filename,
1028                                       unsigned long load_addr,
1029                                       const char* path,
1030                                       struct macho_info* macho_info)
1031 {
1032     BOOL                ret = FALSE;
1033     WCHAR               *s, *t, *fn;
1034     WCHAR*              pathW = NULL;
1035     unsigned            len;
1036
1037     TRACE("(%p, %s, 0x%08lx, %s, %p)\n", hProcess, debugstr_w(filename), load_addr,
1038             debugstr_a(path), macho_info);
1039
1040     if (!path) return FALSE;
1041
1042     len = MultiByteToWideChar(CP_UNIXCP, 0, path, -1, NULL, 0);
1043     pathW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1044     if (!pathW) return FALSE;
1045     MultiByteToWideChar(CP_UNIXCP, 0, path, -1, pathW, len);
1046
1047     for (s = pathW; s && *s; s = (t) ? (t+1) : NULL)
1048     {
1049         t = strchrW(s, ':');
1050         if (t) *t = '\0';
1051         fn = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(filename) + 1 + lstrlenW(s) + 1) * sizeof(WCHAR));
1052         if (!fn) break;
1053         strcpyW(fn, s);
1054         strcatW(fn, S_SlashW);
1055         strcatW(fn, filename);
1056         ret = macho_load_file(hProcess, fn, load_addr, macho_info);
1057         HeapFree(GetProcessHeap(), 0, fn);
1058         if (ret) break;
1059         s = (t) ? (t+1) : NULL;
1060     }
1061
1062     TRACE(" => %d\n", ret);
1063     HeapFree(GetProcessHeap(), 0, pathW);
1064     return ret;
1065 }
1066
1067 /******************************************************************
1068  *              macho_load_file_from_dll_path
1069  *
1070  * Tries to load a Mach-O file from the dll path
1071  */
1072 static BOOL macho_load_file_from_dll_path(HANDLE hProcess,
1073                                           const WCHAR* filename,
1074                                           unsigned long load_addr,
1075                                           struct macho_info* macho_info)
1076 {
1077     BOOL ret = FALSE;
1078     unsigned int index = 0;
1079     const char *path;
1080
1081     TRACE("(%p, %s, 0x%08lx, %p)\n", hProcess, debugstr_w(filename), load_addr,
1082             macho_info);
1083
1084     while (!ret && (path = wine_dll_enum_load_path( index++ )))
1085     {
1086         WCHAR *name;
1087         unsigned len;
1088
1089         len = MultiByteToWideChar(CP_UNIXCP, 0, path, -1, NULL, 0);
1090
1091         name = HeapAlloc( GetProcessHeap(), 0,
1092                           (len + lstrlenW(filename) + 2) * sizeof(WCHAR) );
1093
1094         if (!name) break;
1095         MultiByteToWideChar(CP_UNIXCP, 0, path, -1, name, len);
1096         strcatW( name, S_SlashW );
1097         strcatW( name, filename );
1098         ret = macho_load_file(hProcess, name, load_addr, macho_info);
1099         HeapFree( GetProcessHeap(), 0, name );
1100     }
1101     TRACE(" => %d\n", ret);
1102     return ret;
1103 }
1104
1105 /******************************************************************
1106  *              macho_search_and_load_file
1107  *
1108  * Lookup a file in standard Mach-O locations, and if found, load it
1109  */
1110 static BOOL macho_search_and_load_file(struct process* pcs, const WCHAR* filename,
1111                                        unsigned long load_addr,
1112                                        struct macho_info* macho_info)
1113 {
1114     BOOL                ret = FALSE;
1115     struct module*      module;
1116     static WCHAR        S_libstdcPPW[] = {'l','i','b','s','t','d','c','+','+','\0'};
1117     const WCHAR*        p;
1118
1119     TRACE("(%p/%p, %s, 0x%08lx, %p)\n", pcs, pcs->handle, debugstr_w(filename), load_addr,
1120             macho_info);
1121
1122     if (filename == NULL || *filename == '\0') return FALSE;
1123     if ((module = module_is_already_loaded(pcs, filename)))
1124     {
1125         macho_info->module = module;
1126         module->format_info[DFI_MACHO]->u.macho_info->in_use = 1;
1127         return module->module.SymType;
1128     }
1129
1130     if (strstrW(filename, S_libstdcPPW)) return FALSE; /* We know we can't do it */
1131
1132     /* If has no directories, try LD_LIBRARY_PATH first. */
1133     if (!strchrW(filename, '/'))
1134     {
1135         ret = macho_load_file_from_path(pcs, filename, load_addr,
1136                                       getenv("PATH"), macho_info);
1137     }
1138     /* Try DYLD_LIBRARY_PATH, with just the filename (no directories). */
1139     if (!ret)
1140     {
1141         if ((p = strrchrW(filename, '/'))) p++;
1142         else p = filename;
1143         ret = macho_load_file_from_path(pcs, p, load_addr,
1144                                       getenv("DYLD_LIBRARY_PATH"), macho_info);
1145     }
1146     /* Try the path as given. */
1147     if (!ret)
1148         ret = macho_load_file(pcs, filename, load_addr, macho_info);
1149     /* Try DYLD_FALLBACK_LIBRARY_PATH, with just the filename (no directories). */
1150     if (!ret)
1151     {
1152         ret = macho_load_file_from_path(pcs, p, load_addr,
1153                                       getenv("DYLD_FALLBACK_LIBRARY_PATH"), macho_info);
1154     }
1155     if (!ret && !strchrW(filename, '/'))
1156         ret = macho_load_file_from_dll_path(pcs, filename, load_addr, macho_info);
1157
1158     return ret;
1159 }
1160
1161 /******************************************************************
1162  *              macho_enum_modules_internal
1163  *
1164  * Enumerate Mach-O modules from a running process
1165  */
1166 static BOOL macho_enum_modules_internal(const struct process* pcs,
1167                                         const WCHAR* main_name,
1168                                         enum_modules_cb cb, void* user)
1169 {
1170     struct dyld_all_image_infos image_infos;
1171     struct dyld_image_info*     info_array = NULL;
1172     unsigned long               len;
1173     int                         i;
1174     char                        bufstr[256];
1175     WCHAR                       bufstrW[MAX_PATH];
1176     BOOL                        ret = FALSE;
1177
1178     TRACE("(%p/%p, %s, %p, %p)\n", pcs, pcs->handle, debugstr_w(main_name), cb,
1179             user);
1180
1181     if (!pcs->dbg_hdr_addr ||
1182         !ReadProcessMemory(pcs->handle, (void*)pcs->dbg_hdr_addr,
1183                            &image_infos, sizeof(image_infos), NULL) ||
1184         !image_infos.infoArray)
1185         goto done;
1186     TRACE("Process has %u image infos at %p\n", image_infos.infoArrayCount, image_infos.infoArray);
1187
1188     len = image_infos.infoArrayCount * sizeof(info_array[0]);
1189     info_array = HeapAlloc(GetProcessHeap(), 0, len);
1190     if (!info_array ||
1191         !ReadProcessMemory(pcs->handle, image_infos.infoArray,
1192                            info_array, len, NULL))
1193         goto done;
1194     TRACE("... read image infos\n");
1195
1196     for (i = 0; i < image_infos.infoArrayCount; i++)
1197     {
1198         if (info_array[i].imageFilePath != NULL &&
1199             ReadProcessMemory(pcs->handle, info_array[i].imageFilePath, bufstr, sizeof(bufstr), NULL))
1200         {
1201             bufstr[sizeof(bufstr) - 1] = '\0';
1202             TRACE("[%d] image file %s\n", i, debugstr_a(bufstr));
1203             MultiByteToWideChar(CP_UNIXCP, 0, bufstr, -1, bufstrW, sizeof(bufstrW) / sizeof(WCHAR));
1204             if (main_name && !bufstrW[0]) strcpyW(bufstrW, main_name);
1205             if (!cb(bufstrW, (unsigned long)info_array[i].imageLoadAddress, user)) break;
1206         }
1207     }
1208
1209     ret = TRUE;
1210 done:
1211     HeapFree(GetProcessHeap(), 0, info_array);
1212     return ret;
1213 }
1214
1215 struct macho_sync
1216 {
1217     struct process*     pcs;
1218     struct macho_info   macho_info;
1219 };
1220
1221 static BOOL macho_enum_sync_cb(const WCHAR* name, unsigned long addr, void* user)
1222 {
1223     struct macho_sync*  ms = user;
1224
1225     TRACE("(%s, 0x%08lx, %p)\n", debugstr_w(name), addr, user);
1226     macho_search_and_load_file(ms->pcs, name, addr, &ms->macho_info);
1227     return TRUE;
1228 }
1229
1230 /******************************************************************
1231  *              macho_synchronize_module_list
1232  *
1233  * Rescans the debuggee's modules list and synchronizes it with
1234  * the one from 'pcs', ie:
1235  * - if a module is in debuggee and not in pcs, it's loaded into pcs
1236  * - if a module is in pcs and not in debuggee, it's unloaded from pcs
1237  */
1238 BOOL    macho_synchronize_module_list(struct process* pcs)
1239 {
1240     struct module*      module;
1241     struct macho_sync     ms;
1242
1243     TRACE("(%p/%p)\n", pcs, pcs->handle);
1244
1245     for (module = pcs->lmodules; module; module = module->next)
1246     {
1247         if (module->type == DMT_MACHO && !module->is_virtual)
1248             module->format_info[DFI_MACHO]->u.macho_info->in_use = 0;
1249     }
1250
1251     ms.pcs = pcs;
1252     ms.macho_info.flags = MACHO_INFO_MODULE;
1253     if (!macho_enum_modules_internal(pcs, NULL, macho_enum_sync_cb, &ms))
1254         return FALSE;
1255
1256     module = pcs->lmodules;
1257     while (module)
1258     {
1259         if (module->type == DMT_MACHO && !module->is_virtual &&
1260             !module->format_info[DFI_MACHO]->u.macho_info->in_use &&
1261             !module->format_info[DFI_MACHO]->u.macho_info->is_loader)
1262         {
1263             module_remove(pcs, module);
1264             /* restart all over */
1265             module = pcs->lmodules;
1266         }
1267         else module = module->next;
1268     }
1269     return TRUE;
1270 }
1271
1272 /******************************************************************
1273  *              macho_search_loader
1274  *
1275  * Lookup in a running Mach-O process the loader, and sets its Mach-O link
1276  * address (for accessing the list of loaded images) in pcs.
1277  * If flags is MACHO_INFO_MODULE, the module for the loader is also
1278  * added as a module into pcs.
1279  */
1280 static BOOL macho_search_loader(struct process* pcs, struct macho_info* macho_info)
1281 {
1282     return macho_search_and_load_file(pcs, get_wine_loader_name(), 0, macho_info);
1283 }
1284
1285 /******************************************************************
1286  *              macho_read_wine_loader_dbg_info
1287  *
1288  * Try to find a decent wine executable which could have loaded the debuggee
1289  */
1290 BOOL macho_read_wine_loader_dbg_info(struct process* pcs)
1291 {
1292     struct macho_info     macho_info;
1293
1294     TRACE("(%p/%p)\n", pcs, pcs->handle);
1295     macho_info.flags = MACHO_INFO_DEBUG_HEADER | MACHO_INFO_MODULE;
1296     if (!macho_search_loader(pcs, &macho_info)) return FALSE;
1297     macho_info.module->format_info[DFI_MACHO]->u.macho_info->is_loader = 1;
1298     module_set_module(macho_info.module, S_WineLoaderW);
1299     return (pcs->dbg_hdr_addr = macho_info.dbg_hdr_addr) != 0;
1300 }
1301
1302 /******************************************************************
1303  *              macho_enum_modules
1304  *
1305  * Enumerates the Mach-O loaded modules from a running target (hProc)
1306  * This function doesn't require that someone has called SymInitialize
1307  * on this very process.
1308  */
1309 BOOL macho_enum_modules(HANDLE hProc, enum_modules_cb cb, void* user)
1310 {
1311     struct process      pcs;
1312     struct macho_info   macho_info;
1313     BOOL                ret;
1314
1315     TRACE("(%p, %p, %p)\n", hProc, cb, user);
1316     memset(&pcs, 0, sizeof(pcs));
1317     pcs.handle = hProc;
1318     macho_info.flags = MACHO_INFO_DEBUG_HEADER | MACHO_INFO_NAME;
1319     if (!macho_search_loader(&pcs, &macho_info)) return FALSE;
1320     pcs.dbg_hdr_addr = macho_info.dbg_hdr_addr;
1321     ret = macho_enum_modules_internal(&pcs, macho_info.module_name, cb, user);
1322     HeapFree(GetProcessHeap(), 0, (char*)macho_info.module_name);
1323     return ret;
1324 }
1325
1326 struct macho_load
1327 {
1328     struct process*     pcs;
1329     struct macho_info   macho_info;
1330     const WCHAR*        name;
1331     BOOL                ret;
1332 };
1333
1334 /******************************************************************
1335  *              macho_load_cb
1336  *
1337  * Callback for macho_load_module, used to walk the list of loaded
1338  * modules.
1339  */
1340 static BOOL macho_load_cb(const WCHAR* name, unsigned long addr, void* user)
1341 {
1342     struct macho_load*  ml = user;
1343     const WCHAR*        p;
1344
1345     TRACE("(%s, 0x%08lx, %p)\n", debugstr_w(name), addr, user);
1346
1347     /* memcmp is needed for matches when bufstr contains also version information
1348      * ml->name: libc.so, name: libc.so.6.0
1349      */
1350     p = strrchrW(name, '/');
1351     if (!p++) p = name;
1352     if (!memcmp(p, ml->name, lstrlenW(ml->name) * sizeof(WCHAR)))
1353     {
1354         ml->ret = macho_search_and_load_file(ml->pcs, name, addr, &ml->macho_info);
1355         return FALSE;
1356     }
1357     return TRUE;
1358 }
1359
1360 /******************************************************************
1361  *              macho_load_module
1362  *
1363  * Loads a Mach-O module and stores it in process' module list.
1364  * Also, find module real name and load address from
1365  * the real loaded modules list in pcs address space.
1366  */
1367 struct module*  macho_load_module(struct process* pcs, const WCHAR* name, unsigned long addr)
1368 {
1369     struct macho_load   ml;
1370
1371     TRACE("(%p/%p, %s, 0x%08lx)\n", pcs, pcs->handle, debugstr_w(name), addr);
1372
1373     ml.macho_info.flags = MACHO_INFO_MODULE;
1374     ml.ret = FALSE;
1375
1376     if (pcs->dbg_hdr_addr) /* we're debugging a live target */
1377     {
1378         ml.pcs = pcs;
1379         /* do only the lookup from the filename, not the path (as we lookup module
1380          * name in the process' loaded module list)
1381          */
1382         ml.name = strrchrW(name, '/');
1383         if (!ml.name++) ml.name = name;
1384         ml.ret = FALSE;
1385
1386         if (!macho_enum_modules_internal(pcs, NULL, macho_load_cb, &ml))
1387             return NULL;
1388     }
1389     else if (addr)
1390     {
1391         ml.name = name;
1392         ml.ret = macho_search_and_load_file(pcs, ml.name, addr, &ml.macho_info);
1393     }
1394     if (!ml.ret) return NULL;
1395     assert(ml.macho_info.module);
1396     return ml.macho_info.module;
1397 }
1398
1399 #else  /* HAVE_MACH_O_LOADER_H */
1400
1401 BOOL    macho_synchronize_module_list(struct process* pcs)
1402 {
1403     return FALSE;
1404 }
1405
1406 BOOL macho_fetch_file_info(const WCHAR* name, DWORD_PTR* base,
1407                            DWORD* size, DWORD* checksum)
1408 {
1409     return FALSE;
1410 }
1411
1412 BOOL macho_read_wine_loader_dbg_info(struct process* pcs)
1413 {
1414     return FALSE;
1415 }
1416
1417 BOOL macho_enum_modules(HANDLE hProc, enum_modules_cb cb, void* user)
1418 {
1419     return FALSE;
1420 }
1421
1422 struct module*  macho_load_module(struct process* pcs, const WCHAR* name, unsigned long addr)
1423 {
1424     return NULL;
1425 }
1426
1427 BOOL macho_load_debug_info(struct module* module, struct macho_file_map* fmap)
1428 {
1429     return FALSE;
1430 }
1431 #endif  /* HAVE_MACH_O_LOADER_H */