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