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