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