push cc8bc80451cc24f4d7cf75168b569f0ebfe19547
[wine/hacks.git] / dlls / dbghelp / macho_module.c
blobc0458c60bb28ab9d8d239510479f330ef98998ee
1 /*
2 * File macho_module.c - processing of Mach-O files
3 * Originally based on elf_module.c
5 * Copyright (C) 1996, Eric Youngdale.
6 * 1999-2007 Eric Pouech
7 * 2009 Ken Thomases, CodeWeavers Inc.
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.
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.
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
24 #include "config.h"
25 #include "wine/port.h"
27 #include "dbghelp_private.h"
29 #ifdef __MACH__
31 #include <assert.h>
32 #include <stdarg.h>
33 #ifdef HAVE_SYS_STAT_H
34 # include <sys/stat.h>
35 #endif
36 #ifdef HAVE_SYS_MMAN_H
37 # include <sys/mman.h>
38 #endif
40 #include <mach-o/fat.h>
41 #include <mach-o/loader.h>
42 #include <mach-o/nlist.h>
44 #ifdef HAVE_MACH_O_DYLD_IMAGES_H
45 #include <mach-o/dyld_images.h>
46 #else
47 struct dyld_image_info {
48 const struct mach_header *imageLoadAddress;
49 const char *imageFilePath;
50 uintptr_t imageFileModDate;
53 struct dyld_all_image_infos {
54 uint32_t version;
55 uint32_t infoArrayCount;
56 const struct dyld_image_info *infoArray;
57 void* notification;
58 int processDetachedFromSharedRegion;
60 #endif
62 #include "winternl.h"
63 #include "wine/library.h"
64 #include "wine/debug.h"
66 #ifdef WORDS_BIGENDIAN
67 #define swap_ulong_be_to_host(n) (n)
68 #else
69 #define swap_ulong_be_to_host(n) (RtlUlongByteSwap(n))
70 #endif
72 WINE_DEFAULT_DEBUG_CHANNEL(dbghelp_macho);
75 struct macho_module_info
77 unsigned long load_addr;
78 unsigned short in_use : 1,
79 is_loader : 1;
82 #define MACHO_INFO_DEBUG_HEADER 0x0001
83 #define MACHO_INFO_MODULE 0x0002
84 #define MACHO_INFO_NAME 0x0004
86 struct macho_info
88 unsigned flags; /* IN one (or several) of the MACHO_INFO constants */
89 unsigned long dbg_hdr_addr; /* OUT address of debug header (if MACHO_INFO_DEBUG_HEADER is set) */
90 struct module* module; /* OUT loaded module (if MACHO_INFO_MODULE is set) */
91 const WCHAR* module_name; /* OUT found module name (if MACHO_INFO_NAME is set) */
94 /* structure holding information while handling a Mach-O image */
95 #define BITS_PER_ULONG (sizeof(ULONG) * 8)
96 #define ULONGS_FOR_BITS(nbits) (((nbits) + BITS_PER_ULONG - 1) / BITS_PER_ULONG)
97 struct macho_file_map
99 /* A copy of the Mach-O header for an individual architecture. */
100 struct mach_header mach_header;
102 /* The mapped load commands. */
103 const struct load_command* load_commands;
105 /* The portion of the file which is this architecture. mach_header was
106 * read from arch_offset. */
107 unsigned arch_offset;
108 unsigned arch_size;
110 /* The range of address space covered by all segments. */
111 size_t segs_start;
112 size_t segs_size;
114 /* Map of which sections contain code. Sections are accessed using 1-based
115 * index. Bit 0 of this bitset indicates if the bitset has been initialized. */
116 RTL_BITMAP sect_is_code;
117 ULONG sect_is_code_buff[ULONGS_FOR_BITS(MAX_SECT + 1)];
119 /* The file. */
120 int fd;
123 static void macho_unmap_file(struct macho_file_map* fmap);
125 /******************************************************************
126 * macho_calc_range
128 * For a range (offset & length) of a single architecture within
129 * a Mach-O file, calculate the page-aligned range of the whole file
130 * that encompasses it. For a fat binary, the architecture will
131 * itself be offset within the file, so take that into account.
133 static void macho_calc_range(const struct macho_file_map* fmap, unsigned offset,
134 unsigned len, unsigned* out_aligned_offset,
135 unsigned* out_aligned_end, unsigned* out_aligned_len,
136 unsigned* out_misalign)
138 unsigned pagemask = getpagesize() - 1;
139 unsigned file_offset, misalign;
141 file_offset = fmap->arch_offset + offset;
142 misalign = file_offset & pagemask;
143 *out_aligned_offset = file_offset - misalign;
144 *out_aligned_end = (file_offset + len + pagemask) & ~pagemask;
145 if (out_aligned_len)
146 *out_aligned_len = *out_aligned_end - *out_aligned_offset;
147 if (out_misalign)
148 *out_misalign = misalign;
151 /******************************************************************
152 * macho_map_range
154 * Maps a range (offset, length in bytes) from a Mach-O file into memory
156 static const char* macho_map_range(const struct macho_file_map* fmap, unsigned offset, unsigned len)
158 unsigned misalign, aligned_offset, aligned_map_end, map_size;
159 const void* aligned_ptr;
161 TRACE("(%p/%d, 0x%08x, 0x%08x)\n", fmap, fmap->fd, offset, len);
163 macho_calc_range(fmap, offset, len, &aligned_offset, &aligned_map_end,
164 &map_size, &misalign);
166 aligned_ptr = mmap(NULL, map_size, PROT_READ, MAP_PRIVATE, fmap->fd, aligned_offset);
168 TRACE("Mapped (0x%08x - 0x%08x) to %p\n", aligned_offset, aligned_map_end, aligned_ptr);
170 if (aligned_ptr == MAP_FAILED) return MACHO_NO_MAP;
171 return (const char*)aligned_ptr + misalign;
174 /******************************************************************
175 * macho_unmap_range
177 * Unmaps a range (offset, length in bytes) of a Mach-O file from memory
179 static void macho_unmap_range(const void** mapped, const struct macho_file_map* fmap,
180 unsigned offset, unsigned len)
182 TRACE("(%p, %p/%d, 0x%08x, 0x%08x)\n", mapped, fmap, fmap->fd, offset, len);
184 if (mapped && *mapped != MACHO_NO_MAP)
186 unsigned misalign, aligned_offset, aligned_map_end, map_size;
187 void* aligned_ptr;
189 macho_calc_range(fmap, offset, len, &aligned_offset, &aligned_map_end,
190 &map_size, &misalign);
192 aligned_ptr = (char*)*mapped - misalign;
193 if (munmap(aligned_ptr, map_size) < 0)
194 WARN("Couldn't unmap the range\n");
195 TRACE("Unmapped (0x%08x - 0x%08x) from %p - %p\n", aligned_offset, aligned_map_end, aligned_ptr, (char*)aligned_ptr + map_size);
196 *mapped = MACHO_NO_MAP;
200 /******************************************************************
201 * macho_map_ranges
203 * Maps two ranges (offset, length in bytes) from a Mach-O file
204 * into memory. If the two ranges overlap, use one mmap so that
205 * the munmap doesn't fragment the mapping.
207 static BOOL macho_map_ranges(const struct macho_file_map* fmap,
208 unsigned offset1, unsigned len1,
209 unsigned offset2, unsigned len2,
210 const void** mapped1, const void** mapped2)
212 unsigned aligned_offset1, aligned_map_end1;
213 unsigned aligned_offset2, aligned_map_end2;
215 TRACE("(%p/%d, 0x%08x, 0x%08x, 0x%08x, 0x%08x, %p, %p)\n", fmap, fmap->fd,
216 offset1, len1, offset2, len2, mapped1, mapped2);
218 macho_calc_range(fmap, offset1, len1, &aligned_offset1, &aligned_map_end1, NULL, NULL);
219 macho_calc_range(fmap, offset2, len2, &aligned_offset2, &aligned_map_end2, NULL, NULL);
221 if (aligned_map_end1 < aligned_offset2 || aligned_map_end2 < aligned_offset1)
223 *mapped1 = macho_map_range(fmap, offset1, len1);
224 if (*mapped1 != MACHO_NO_MAP)
226 *mapped2 = macho_map_range(fmap, offset2, len2);
227 if (*mapped2 == MACHO_NO_MAP)
228 macho_unmap_range(mapped1, fmap, offset1, len1);
231 else
233 if (offset1 < offset2)
235 *mapped1 = macho_map_range(fmap, offset1, offset2 + len2 - offset1);
236 if (*mapped1 != MACHO_NO_MAP)
237 *mapped2 = (const char*)*mapped1 + offset2 - offset1;
239 else
241 *mapped2 = macho_map_range(fmap, offset2, offset1 + len1 - offset2);
242 if (*mapped2 != MACHO_NO_MAP)
243 *mapped1 = (const char*)*mapped2 + offset1 - offset2;
247 TRACE(" => %p, %p\n", *mapped1, *mapped2);
249 return (*mapped1 != MACHO_NO_MAP) && (*mapped2 != MACHO_NO_MAP);
252 /******************************************************************
253 * macho_unmap_ranges
255 * Unmaps two ranges (offset, length in bytes) of a Mach-O file
256 * from memory. Use for ranges which were mapped by
257 * macho_map_ranges.
259 static void macho_unmap_ranges(const struct macho_file_map* fmap,
260 unsigned offset1, unsigned len1,
261 unsigned offset2, unsigned len2,
262 const void** mapped1, const void** mapped2)
264 unsigned aligned_offset1, aligned_map_end1;
265 unsigned aligned_offset2, aligned_map_end2;
267 TRACE("(%p/%d, 0x%08x, 0x%08x, 0x%08x, 0x%08x, %p/%p, %p/%p)\n", fmap, fmap->fd,
268 offset1, len1, offset2, len2, mapped1, *mapped1, mapped2, *mapped2);
270 macho_calc_range(fmap, offset1, len1, &aligned_offset1, &aligned_map_end1, NULL, NULL);
271 macho_calc_range(fmap, offset2, len2, &aligned_offset2, &aligned_map_end2, NULL, NULL);
273 if (aligned_map_end1 < aligned_offset2 || aligned_map_end2 < aligned_offset1)
275 macho_unmap_range(mapped1, fmap, offset1, len1);
276 macho_unmap_range(mapped2, fmap, offset2, len2);
278 else
280 if (offset1 < offset2)
282 macho_unmap_range(mapped1, fmap, offset1, offset2 + len2 - offset1);
283 *mapped2 = MACHO_NO_MAP;
285 else
287 macho_unmap_range(mapped2, fmap, offset2, offset1 + len1 - offset2);
288 *mapped1 = MACHO_NO_MAP;
293 /******************************************************************
294 * macho_map_load_commands
296 * Maps the load commands from a Mach-O file into memory
298 static const struct load_command* macho_map_load_commands(struct macho_file_map* fmap)
300 if (fmap->load_commands == MACHO_NO_MAP)
302 fmap->load_commands = (const struct load_command*) macho_map_range(
303 fmap, sizeof(fmap->mach_header), fmap->mach_header.sizeofcmds);
304 TRACE("Mapped load commands: %p\n", fmap->load_commands);
307 return fmap->load_commands;
310 /******************************************************************
311 * macho_unmap_load_commands
313 * Unmaps the load commands of a Mach-O file from memory
315 static void macho_unmap_load_commands(struct macho_file_map* fmap)
317 if (fmap->load_commands != MACHO_NO_MAP)
319 TRACE("Unmapping load commands: %p\n", fmap->load_commands);
320 macho_unmap_range((const void**)&fmap->load_commands, fmap,
321 sizeof(fmap->mach_header), fmap->mach_header.sizeofcmds);
325 /******************************************************************
326 * macho_next_load_command
328 * Advance to the next load command
330 static const struct load_command* macho_next_load_command(const struct load_command* lc)
332 return (const struct load_command*)((const char*)lc + lc->cmdsize);
335 /******************************************************************
336 * macho_enum_load_commands
338 * Enumerates the load commands for a Mach-O file, selecting by
339 * the command type, calling a callback for each. If the callback
340 * returns <0, that indicates an error. If it returns >0, that means
341 * it's not interested in getting any more load commands.
342 * If this function returns <0, that's an error produced by the
343 * callback. If >=0, that's the count of load commands successfully
344 * processed.
346 static int macho_enum_load_commands(struct macho_file_map* fmap, unsigned cmd,
347 int (*cb)(struct macho_file_map*, const struct load_command*, void*),
348 void* user)
350 const struct load_command* lc;
351 int i;
352 int count = 0;
354 TRACE("(%p/%d, %u, %p, %p)\n", fmap, fmap->fd, cmd, cb, user);
356 if ((lc = macho_map_load_commands(fmap)) == MACHO_NO_MAP) return -1;
358 TRACE("%d total commands\n", fmap->mach_header.ncmds);
360 for (i = 0; i < fmap->mach_header.ncmds; i++, lc = macho_next_load_command(lc))
362 int result;
364 if (cmd && cmd != lc->cmd) continue;
365 count++;
367 result = cb(fmap, lc, user);
368 TRACE("load_command[%d] (%p), cmd %u; callback => %d\n", i, lc, lc->cmd, result);
369 if (result) return (result < 0) ? result : count;
372 return count;
375 /******************************************************************
376 * macho_accum_segs_range
378 * Callback for macho_enum_load_commands. Accumulates the address
379 * range covered by the segments of a Mach-O file. All commands
380 * are expected to be of LC_SEGMENT type.
382 static int macho_accum_segs_range(struct macho_file_map* fmap,
383 const struct load_command* lc, void* user)
385 const struct segment_command* sc = (const struct segment_command*)lc;
386 unsigned tmp, page_mask = getpagesize() - 1;
388 TRACE("(%p/%d, %p, %p) before: 0x%08x - 0x%08x\n", fmap, fmap->fd, lc, user,
389 (unsigned)fmap->segs_start, (unsigned)fmap->segs_size);
390 TRACE("Segment command vm: 0x%08x - 0x%08x\n", (unsigned)sc->vmaddr,
391 (unsigned)sc->vmaddr + sc->vmsize);
393 if (!strncmp(sc->segname, "WINE_DOS", sizeof(sc->segname)) ||
394 !strncmp(sc->segname, "WINE_OLE32", sizeof(sc->segname)) ||
395 !strncmp(sc->segname, "WINE_SHARED_HEAP", sizeof(sc->segname)))
397 TRACE("Ignoring special Wine segment %s\n", debugstr_an(sc->segname, sizeof(sc->segname)));
398 return 0;
401 /* If this segment starts before previously-known earliest, record
402 * new earliest. */
403 if (sc->vmaddr < fmap->segs_start)
404 fmap->segs_start = sc->vmaddr;
406 /* If this segment extends beyond previously-known furthest, record
407 * new furthest. */
408 tmp = (sc->vmaddr + sc->vmsize + page_mask) & ~page_mask;
409 if (fmap->segs_size < tmp) fmap->segs_size = tmp;
411 TRACE("after: 0x%08x - 0x%08x\n", (unsigned)fmap->segs_start, (unsigned)fmap->segs_size);
413 return 0;
416 /******************************************************************
417 * macho_map_file
419 * Maps a Mach-O file into memory (and checks it's a real Mach-O file)
421 static BOOL macho_map_file(const WCHAR* filenameW, struct macho_file_map* fmap)
423 struct fat_header fat_header;
424 struct stat statbuf;
425 int i;
426 char* filename;
427 unsigned len;
428 BOOL ret = FALSE;
430 TRACE("(%s, %p)\n", debugstr_w(filenameW), fmap);
432 fmap->fd = -1;
433 fmap->load_commands = MACHO_NO_MAP;
434 RtlInitializeBitMap(&fmap->sect_is_code, fmap->sect_is_code_buff, MAX_SECT + 1);
436 len = WideCharToMultiByte(CP_UNIXCP, 0, filenameW, -1, NULL, 0, NULL, NULL);
437 if (!(filename = HeapAlloc(GetProcessHeap(), 0, len))) return FALSE;
438 WideCharToMultiByte(CP_UNIXCP, 0, filenameW, -1, filename, len, NULL, NULL);
440 /* check that the file exists */
441 if (stat(filename, &statbuf) == -1 || S_ISDIR(statbuf.st_mode)) goto done;
443 /* Now open the file, so that we can mmap() it. */
444 if ((fmap->fd = open(filename, O_RDONLY)) == -1) goto done;
446 if (read(fmap->fd, &fat_header, sizeof(fat_header)) != sizeof(fat_header))
447 goto done;
448 TRACE("... got possible fat header\n");
450 /* Fat header is always in big-endian order. */
451 if (swap_ulong_be_to_host(fat_header.magic) == FAT_MAGIC)
453 int narch = swap_ulong_be_to_host(fat_header.nfat_arch);
454 for (i = 0; i < narch; i++)
456 struct fat_arch fat_arch;
457 if (read(fmap->fd, &fat_arch, sizeof(fat_arch)) != sizeof(fat_arch))
458 goto done;
459 if (swap_ulong_be_to_host(fat_arch.cputype) == CPU_TYPE_X86)
461 fmap->arch_offset = swap_ulong_be_to_host(fat_arch.offset);
462 fmap->arch_size = swap_ulong_be_to_host(fat_arch.size);
463 break;
466 if (i >= narch) goto done;
467 TRACE("... found x86 arch\n");
469 else
471 fmap->arch_offset = 0;
472 fmap->arch_size = statbuf.st_size;
473 TRACE("... not a fat header\n");
476 /* Individual architecture (standalone or within a fat file) is in its native byte order. */
477 lseek(fmap->fd, fmap->arch_offset, SEEK_SET);
478 if (read(fmap->fd, &fmap->mach_header, sizeof(fmap->mach_header)) != sizeof(fmap->mach_header))
479 goto done;
480 TRACE("... got possible Mach header\n");
481 /* and check for a Mach-O header */
482 if (fmap->mach_header.magic != MH_MAGIC ||
483 fmap->mach_header.cputype != CPU_TYPE_X86) goto done;
484 /* Make sure the file type is one of the ones we expect. */
485 switch (fmap->mach_header.filetype)
487 case MH_EXECUTE:
488 case MH_DYLIB:
489 case MH_DYLINKER:
490 case MH_BUNDLE:
491 break;
492 default:
493 goto done;
495 TRACE("... verified Mach x86 header\n");
497 fmap->segs_size = 0;
498 fmap->segs_start = ~0L;
500 if (macho_enum_load_commands(fmap, LC_SEGMENT, macho_accum_segs_range, NULL) < 0)
501 goto done;
503 fmap->segs_size -= fmap->segs_start;
504 TRACE("segs_start: 0x%08x, segs_size: 0x%08x\n", (unsigned)fmap->segs_start,
505 (unsigned)fmap->segs_size);
507 ret = TRUE;
508 done:
509 if (!ret)
510 macho_unmap_file(fmap);
511 HeapFree(GetProcessHeap(), 0, filename);
512 return ret;
515 /******************************************************************
516 * macho_unmap_file
518 * Unmaps a Mach-O file from memory (previously mapped with macho_map_file)
520 static void macho_unmap_file(struct macho_file_map* fmap)
522 TRACE("(%p/%d)\n", fmap, fmap->fd);
523 if (fmap->fd != -1)
525 macho_unmap_load_commands(fmap);
526 close(fmap->fd);
527 fmap->fd = -1;
531 /******************************************************************
532 * macho_fill_sect_is_code
534 * Callback for macho_enum_load_commands. Determines which segments
535 * of a Mach-O file contain code. All commands are expected to be
536 * of LC_SEGMENT type.
538 static int macho_fill_sect_is_code(struct macho_file_map* fmap,
539 const struct load_command* lc, void* user)
541 const struct segment_command* sc = (const struct segment_command*)lc;
542 const struct section* sections;
543 int* cursect = user;
544 int i;
546 TRACE("(%p/%d, %p, %p/%d) scanning %u sections\n", fmap, fmap->fd, lc,
547 cursect, *cursect, sc->nsects);
549 sections = (const struct section*)(sc + 1);
550 for (i = 0; i < sc->nsects; i++)
552 if (*cursect > MAX_SECT) return -1;
553 (*cursect)++;
555 if (!(sections[i].flags & SECTION_TYPE) &&
556 (sections[i].flags & (S_ATTR_PURE_INSTRUCTIONS|S_ATTR_SOME_INSTRUCTIONS)))
557 RtlSetBits(&fmap->sect_is_code, *cursect, 1);
558 else
559 RtlClearBits(&fmap->sect_is_code, *cursect, 1);
560 TRACE("Section %d (%d of this segment) is%s code\n", *cursect, i,
561 (RtlAreBitsSet(&fmap->sect_is_code, *cursect, 1) ? "" : " not"));
564 return 0;
567 /******************************************************************
568 * macho_sect_is_code
570 * Checks if a section, identified by sectidx which is a 1-based
571 * index into the sections of all segments, in order of load
572 * commands, contains code.
574 static BOOL macho_sect_is_code(struct macho_file_map* fmap, unsigned char sectidx)
576 TRACE("(%p/%d, %u)\n", fmap, fmap->fd, sectidx);
578 if (!RtlAreBitsSet(&fmap->sect_is_code, 0, 1))
580 int cursect = 0;
581 if (macho_enum_load_commands(fmap, LC_SEGMENT, macho_fill_sect_is_code, &cursect) < 0)
582 WARN("Couldn't load sect_is_code map\n");
583 RtlSetBits(&fmap->sect_is_code, 0, 1);
586 return RtlAreBitsSet(&fmap->sect_is_code, sectidx, 1);
589 struct symtab_elt
591 struct hash_table_elt ht_elt;
592 struct symt_compiland* compiland;
593 unsigned long addr;
594 unsigned char is_code:1,
595 is_public:1,
596 is_global:1,
597 used:1;
600 struct macho_debug_info
602 struct macho_file_map* fmap;
603 struct module* module;
604 struct pool pool;
605 struct hash_table ht_symtab;
608 /******************************************************************
609 * macho_stabs_def_cb
611 * Callback for stabs_parse. Collect symbol definitions.
613 static void macho_stabs_def_cb(struct module* module, unsigned long load_offset,
614 const char* name, unsigned long offset,
615 BOOL is_public, BOOL is_global, unsigned char sectidx,
616 struct symt_compiland* compiland, void* user)
618 struct macho_debug_info* mdi = user;
619 struct symtab_elt* ste;
621 TRACE("(%p, 0x%08lx, %s, 0x%08lx, %d, %d, %u, %p, %p/%p/%d)\n", module, load_offset,
622 debugstr_a(name), offset, is_public, is_global, sectidx,
623 compiland, mdi, mdi->fmap, mdi->fmap->fd);
625 /* Defer the creation of new non-debugging symbols until after we've
626 * finished parsing the stabs. */
627 ste = pool_alloc(&mdi->pool, sizeof(*ste));
628 ste->ht_elt.name = pool_strdup(&mdi->pool, name);
629 ste->compiland = compiland;
630 ste->addr = load_offset + offset;
631 ste->is_code = !!macho_sect_is_code(mdi->fmap, sectidx);
632 ste->is_public = !!is_public;
633 ste->is_global = !!is_global;
634 ste->used = 0;
635 hash_table_add(&mdi->ht_symtab, &ste->ht_elt);
638 /******************************************************************
639 * macho_parse_symtab
641 * Callback for macho_enum_load_commands. Processes the LC_SYMTAB
642 * load commands from the Mach-O file.
644 static int macho_parse_symtab(struct macho_file_map* fmap,
645 const struct load_command* lc, void* user)
647 const struct symtab_command* sc = (const struct symtab_command*)lc;
648 struct macho_debug_info* mdi = user;
649 const struct nlist* stab;
650 const char* stabstr;
651 int ret = 0;
653 TRACE("(%p/%d, %p, %p) %u syms at 0x%08x, strings 0x%08x - 0x%08x\n", fmap, fmap->fd, lc,
654 user, sc->nsyms, sc->symoff, sc->stroff, sc->stroff + sc->strsize);
656 if (!macho_map_ranges(fmap, sc->symoff, sc->nsyms * sizeof(struct nlist),
657 sc->stroff, sc->strsize, (const void**)&stab, (const void**)&stabstr))
658 return 0;
660 if (!stabs_parse(mdi->module, mdi->module->macho_info->load_addr - fmap->segs_start,
661 stab, sc->nsyms * sizeof(struct nlist),
662 stabstr, sc->strsize, macho_stabs_def_cb, mdi))
663 ret = -1;
665 macho_unmap_ranges(fmap, sc->symoff, sc->nsyms * sizeof(struct nlist),
666 sc->stroff, sc->strsize, (const void**)&stab, (const void**)&stabstr);
668 return ret;
671 /******************************************************************
672 * macho_finish_stabs
674 * Integrate the non-debugging symbols we've gathered into the
675 * symbols that were generated during stabs parsing.
677 static void macho_finish_stabs(struct module* module, struct hash_table* ht_symtab)
679 struct hash_table_iter hti_ours;
680 struct symtab_elt* ste;
681 BOOL adjusted = FALSE;
683 TRACE("(%p, %p)\n", module, ht_symtab);
685 /* For each of our non-debugging symbols, see if it can provide some
686 * missing details to one of the module's known symbols. */
687 hash_table_iter_init(ht_symtab, &hti_ours, NULL);
688 while ((ste = hash_table_iter_up(&hti_ours)))
690 struct hash_table_iter hti_modules;
691 void* ptr;
692 struct symt_ht* sym;
693 struct symt_function* func;
694 struct symt_data* data;
696 hash_table_iter_init(&module->ht_symbols, &hti_modules, ste->ht_elt.name);
697 while ((ptr = hash_table_iter_up(&hti_modules)))
699 sym = GET_ENTRY(ptr, struct symt_ht, hash_elt);
701 if (strcmp(sym->hash_elt.name, ste->ht_elt.name))
702 continue;
704 switch (sym->symt.tag)
706 case SymTagFunction:
707 func = (struct symt_function*)sym;
708 if (func->address == module->macho_info->load_addr)
710 TRACE("Adjusting function %p/%s!%s from 0x%08lx to 0x%08lx\n", func,
711 debugstr_w(module->module.ModuleName), sym->hash_elt.name,
712 func->address, ste->addr);
713 func->address = ste->addr;
714 adjusted = TRUE;
716 if (func->address == ste->addr)
717 ste->used = 1;
718 break;
719 case SymTagData:
720 data = (struct symt_data*)sym;
721 switch (data->kind)
723 case DataIsGlobal:
724 case DataIsFileStatic:
725 if (data->u.var.offset == module->macho_info->load_addr)
727 TRACE("Adjusting data symbol %p/%s!%s from 0x%08lx to 0x%08lx\n",
728 data, debugstr_w(module->module.ModuleName), sym->hash_elt.name,
729 data->u.var.offset, ste->addr);
730 data->u.var.offset = ste->addr;
731 adjusted = TRUE;
733 if (data->u.var.offset == ste->addr)
735 enum DataKind new_kind;
737 new_kind = ste->is_global ? DataIsGlobal : DataIsFileStatic;
738 if (data->kind != new_kind)
740 WARN("Changing kind for %p/%s!%s from %d to %d\n", sym,
741 debugstr_w(module->module.ModuleName), sym->hash_elt.name,
742 (int)data->kind, (int)new_kind);
743 data->kind = new_kind;
744 adjusted = TRUE;
746 ste->used = 1;
748 break;
749 default:;
751 break;
752 default:
753 TRACE("Ignoring tag %u\n", sym->symt.tag);
754 break;
759 if (adjusted)
761 /* since we may have changed some addresses, mark the module to be resorted */
762 module->sortlist_valid = FALSE;
765 /* Mark any of our non-debugging symbols which fall on an already-used
766 * address as "used". This allows us to skip them in the next loop,
767 * below. We do this in separate loops because symt_new_* marks the
768 * list as needing sorting and symt_find_nearest sorts if needed,
769 * causing thrashing. */
770 if (!(dbghelp_options & SYMOPT_PUBLICS_ONLY))
772 hash_table_iter_init(ht_symtab, &hti_ours, NULL);
773 while ((ste = hash_table_iter_up(&hti_ours)))
775 struct symt_ht* sym;
776 ULONG64 addr;
778 if (ste->used) continue;
780 sym = symt_find_nearest(module, ste->addr);
781 if (sym)
782 symt_get_info(&sym->symt, TI_GET_ADDRESS, &addr);
783 if (sym && ste->addr == addr)
785 ULONG64 size = 0;
786 DWORD kind = -1;
788 ste->used = 1;
790 /* If neither symbol has a correct size (ours never does), we
791 * consider them both to be markers. No warning is needed in
792 * that case.
793 * Also, we check that we don't have two symbols, one local, the other
794 * global, which is legal.
796 symt_get_info(&sym->symt, TI_GET_LENGTH, &size);
797 symt_get_info(&sym->symt, TI_GET_DATAKIND, &kind);
798 if (size && kind == (ste->is_global ? DataIsGlobal : DataIsFileStatic))
799 FIXME("Duplicate in %s: %s<%08lx> %s<%s-%s>\n",
800 debugstr_w(module->module.ModuleName),
801 ste->ht_elt.name, ste->addr,
802 sym->hash_elt.name,
803 wine_dbgstr_longlong(addr), wine_dbgstr_longlong(size));
808 /* For any of our remaining non-debugging symbols which have no match
809 * among the module's known symbols, add them as new symbols. */
810 hash_table_iter_init(ht_symtab, &hti_ours, NULL);
811 while ((ste = hash_table_iter_up(&hti_ours)))
813 if (!(dbghelp_options & SYMOPT_PUBLICS_ONLY) && !ste->used)
815 if (ste->is_code)
817 symt_new_function(module, ste->compiland, ste->ht_elt.name,
818 ste->addr, 0, NULL);
820 else
822 symt_new_global_variable(module, ste->compiland, ste->ht_elt.name,
823 !ste->is_global, ste->addr, 0, NULL);
826 ste->used = 1;
829 if (ste->is_public && !(dbghelp_options & SYMOPT_NO_PUBLICS))
831 symt_new_public(module, ste->compiland, ste->ht_elt.name,
832 ste->addr, 0, ste->is_code, ste->is_code);
837 /******************************************************************
838 * macho_load_debug_info_from_map
840 * Loads the symbolic information from a Mach-O module.
841 * Returns
842 * FALSE if the file doesn't contain symbolic info (or this info
843 * cannot be read or parsed)
844 * TRUE on success
846 static BOOL macho_load_debug_info_from_map(struct module* module,
847 struct macho_file_map* fmap)
849 BOOL ret = FALSE;
850 struct macho_debug_info mdi;
851 int result;
853 TRACE("(%p, %p/%d)\n", module, fmap, fmap->fd);
855 module->module.SymType = SymExport;
857 mdi.fmap = fmap;
858 mdi.module = module;
859 pool_init(&mdi.pool, 65536);
860 hash_table_init(&mdi.pool, &mdi.ht_symtab, 256);
861 result = macho_enum_load_commands(fmap, LC_SYMTAB, macho_parse_symtab, &mdi);
862 if (result > 0)
863 ret = TRUE;
864 else if (result < 0)
865 WARN("Couldn't correctly read stabs\n");
867 macho_finish_stabs(module, &mdi.ht_symtab);
869 pool_destroy(&mdi.pool);
870 return ret;
873 /******************************************************************
874 * macho_load_debug_info
876 * Loads Mach-O debugging information from the module image file.
878 BOOL macho_load_debug_info(struct module* module, struct macho_file_map* fmap)
880 BOOL ret = TRUE;
881 struct macho_file_map my_fmap;
883 TRACE("(%p, %p/%d)\n", module, fmap, fmap ? fmap->fd : -1);
885 if (module->type != DMT_MACHO || !module->macho_info)
887 ERR("Bad Mach-O module '%s'\n", debugstr_w(module->module.LoadedImageName));
888 return FALSE;
891 if (!fmap)
893 fmap = &my_fmap;
894 ret = macho_map_file(module->module.LoadedImageName, fmap);
896 if (ret)
897 ret = macho_load_debug_info_from_map(module, fmap);
899 if (fmap == &my_fmap) macho_unmap_file(fmap);
900 return ret;
903 /******************************************************************
904 * macho_fetch_file_info
906 * Gathers some more information for a Mach-O module from a given file
908 BOOL macho_fetch_file_info(const WCHAR* name, DWORD* base,
909 DWORD* size, DWORD* checksum)
911 struct macho_file_map fmap;
913 TRACE("(%s, %p, %p, %p)\n", debugstr_w(name), base, size, checksum);
915 if (!macho_map_file(name, &fmap)) return FALSE;
916 if (base) *base = fmap.segs_start;
917 *size = fmap.segs_size;
918 *checksum = calc_crc32(fmap.fd);
919 macho_unmap_file(&fmap);
920 return TRUE;
923 /******************************************************************
924 * macho_load_file
926 * Loads the information for Mach-O module stored in 'filename'.
927 * The module has been loaded at 'load_addr' address.
928 * returns
929 * FALSE if the file cannot be found/opened or if the file doesn't
930 * contain symbolic info (or this info cannot be read or parsed)
931 * TRUE on success
933 static BOOL macho_load_file(struct process* pcs, const WCHAR* filename,
934 unsigned long load_addr, struct macho_info* macho_info)
936 BOOL ret = TRUE;
937 struct macho_file_map fmap;
939 TRACE("(%p/%p, %s, 0x%08lx, %p/0x%08x)\n", pcs, pcs->handle, debugstr_w(filename),
940 load_addr, macho_info, macho_info->flags);
942 if (!macho_map_file(filename, &fmap)) return FALSE;
944 /* Find the dynamic loader's table of images loaded into the process.
946 if (macho_info->flags & MACHO_INFO_DEBUG_HEADER)
948 static void* dyld_all_image_infos_addr;
950 /* This symbol should be in the same place in all processes. */
951 if (!dyld_all_image_infos_addr)
953 struct nlist nl[2];
954 memset(nl, 0, sizeof(nl));
955 nl[0].n_un.n_name = (char*)"_dyld_all_image_infos";
956 if (!nlist("/usr/lib/dyld", nl))
957 dyld_all_image_infos_addr = (void*)nl[0].n_value;
960 if (dyld_all_image_infos_addr)
961 macho_info->dbg_hdr_addr = (unsigned long)dyld_all_image_infos_addr;
962 else
963 ret = FALSE;
964 TRACE("dbg_hdr_addr = 0x%08lx\n", macho_info->dbg_hdr_addr);
967 if (macho_info->flags & MACHO_INFO_MODULE)
969 struct macho_module_info *macho_module_info =
970 HeapAlloc(GetProcessHeap(), 0, sizeof(struct macho_module_info));
971 if (!macho_module_info) goto leave;
972 macho_info->module = module_new(pcs, filename, DMT_MACHO, FALSE, load_addr,
973 fmap.segs_size, 0, calc_crc32(fmap.fd));
974 if (!macho_info->module)
976 HeapFree(GetProcessHeap(), 0, macho_module_info);
977 goto leave;
979 macho_info->module->macho_info = macho_module_info;
980 macho_info->module->macho_info->load_addr = load_addr;
982 if (dbghelp_options & SYMOPT_DEFERRED_LOADS)
983 macho_info->module->module.SymType = SymDeferred;
984 else if (!macho_load_debug_info(macho_info->module, &fmap))
985 ret = FALSE;
987 macho_info->module->macho_info->in_use = 1;
988 macho_info->module->macho_info->is_loader = 0;
989 TRACE("module = %p\n", macho_info->module);
992 if (macho_info->flags & MACHO_INFO_NAME)
994 WCHAR* ptr;
995 ptr = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(filename) + 1) * sizeof(WCHAR));
996 if (ptr)
998 strcpyW(ptr, filename);
999 macho_info->module_name = ptr;
1001 else ret = FALSE;
1002 TRACE("module_name = %p %s\n", macho_info->module_name, debugstr_w(macho_info->module_name));
1004 leave:
1005 macho_unmap_file(&fmap);
1007 TRACE(" => %d\n", ret);
1008 return ret;
1011 /******************************************************************
1012 * macho_load_file_from_path
1013 * Tries to load a Mach-O file from a set of paths (separated by ':')
1015 static BOOL macho_load_file_from_path(HANDLE hProcess,
1016 const WCHAR* filename,
1017 unsigned long load_addr,
1018 const char* path,
1019 struct macho_info* macho_info)
1021 BOOL ret = FALSE;
1022 WCHAR *s, *t, *fn;
1023 WCHAR* pathW = NULL;
1024 unsigned len;
1026 TRACE("(%p, %s, 0x%08lx, %s, %p)\n", hProcess, debugstr_w(filename), load_addr,
1027 debugstr_a(path), macho_info);
1029 if (!path) return FALSE;
1031 len = MultiByteToWideChar(CP_UNIXCP, 0, path, -1, NULL, 0);
1032 pathW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1033 if (!pathW) return FALSE;
1034 MultiByteToWideChar(CP_UNIXCP, 0, path, -1, pathW, len);
1036 for (s = pathW; s && *s; s = (t) ? (t+1) : NULL)
1038 t = strchrW(s, ':');
1039 if (t) *t = '\0';
1040 fn = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(filename) + 1 + lstrlenW(s) + 1) * sizeof(WCHAR));
1041 if (!fn) break;
1042 strcpyW(fn, s);
1043 strcatW(fn, S_SlashW);
1044 strcatW(fn, filename);
1045 ret = macho_load_file(hProcess, fn, load_addr, macho_info);
1046 HeapFree(GetProcessHeap(), 0, fn);
1047 if (ret) break;
1048 s = (t) ? (t+1) : NULL;
1051 TRACE(" => %d\n", ret);
1052 HeapFree(GetProcessHeap(), 0, pathW);
1053 return ret;
1056 /******************************************************************
1057 * macho_load_file_from_dll_path
1059 * Tries to load a Mach-O file from the dll path
1061 static BOOL macho_load_file_from_dll_path(HANDLE hProcess,
1062 const WCHAR* filename,
1063 unsigned long load_addr,
1064 struct macho_info* macho_info)
1066 BOOL ret = FALSE;
1067 unsigned int index = 0;
1068 const char *path;
1070 TRACE("(%p, %s, 0x%08lx, %p)\n", hProcess, debugstr_w(filename), load_addr,
1071 macho_info);
1073 while (!ret && (path = wine_dll_enum_load_path( index++ )))
1075 WCHAR *name;
1076 unsigned len;
1078 len = MultiByteToWideChar(CP_UNIXCP, 0, path, -1, NULL, 0);
1080 name = HeapAlloc( GetProcessHeap(), 0,
1081 (len + lstrlenW(filename) + 2) * sizeof(WCHAR) );
1083 if (!name) break;
1084 MultiByteToWideChar(CP_UNIXCP, 0, path, -1, name, len);
1085 strcatW( name, S_SlashW );
1086 strcatW( name, filename );
1087 ret = macho_load_file(hProcess, name, load_addr, macho_info);
1088 HeapFree( GetProcessHeap(), 0, name );
1090 TRACE(" => %d\n", ret);
1091 return ret;
1094 /******************************************************************
1095 * macho_search_and_load_file
1097 * Lookup a file in standard Mach-O locations, and if found, load it
1099 static BOOL macho_search_and_load_file(struct process* pcs, const WCHAR* filename,
1100 unsigned long load_addr,
1101 struct macho_info* macho_info)
1103 BOOL ret = FALSE;
1104 struct module* module;
1105 static WCHAR S_libstdcPPW[] = {'l','i','b','s','t','d','c','+','+','\0'};
1106 const WCHAR* p;
1108 TRACE("(%p/%p, %s, 0x%08lx, %p)\n", pcs, pcs->handle, debugstr_w(filename), load_addr,
1109 macho_info);
1111 if (filename == NULL || *filename == '\0') return FALSE;
1112 if ((module = module_is_already_loaded(pcs, filename)))
1114 macho_info->module = module;
1115 module->macho_info->in_use = 1;
1116 return module->module.SymType;
1119 if (strstrW(filename, S_libstdcPPW)) return FALSE; /* We know we can't do it */
1121 /* If has no directories, try LD_LIBRARY_PATH first. */
1122 if (!strchrW(filename, '/'))
1124 ret = macho_load_file_from_path(pcs, filename, load_addr,
1125 getenv("PATH"), macho_info);
1127 /* Try DYLD_LIBRARY_PATH, with just the filename (no directories). */
1128 if (!ret)
1130 if ((p = strrchrW(filename, '/'))) p++;
1131 else p = filename;
1132 ret = macho_load_file_from_path(pcs, p, load_addr,
1133 getenv("DYLD_LIBRARY_PATH"), macho_info);
1135 /* Try the path as given. */
1136 if (!ret)
1137 ret = macho_load_file(pcs, filename, load_addr, macho_info);
1138 /* Try DYLD_FALLBACK_LIBRARY_PATH, with just the filename (no directories). */
1139 if (!ret)
1141 ret = macho_load_file_from_path(pcs, p, load_addr,
1142 getenv("DYLD_FALLBACK_LIBRARY_PATH"), macho_info);
1144 if (!ret && !strchrW(filename, '/'))
1145 ret = macho_load_file_from_dll_path(pcs, filename, load_addr, macho_info);
1147 return ret;
1150 /******************************************************************
1151 * macho_enum_modules_internal
1153 * Enumerate Mach-O modules from a running process
1155 static BOOL macho_enum_modules_internal(const struct process* pcs,
1156 const WCHAR* main_name,
1157 enum_modules_cb cb, void* user)
1159 struct dyld_all_image_infos image_infos;
1160 struct dyld_image_info* info_array = NULL;
1161 unsigned long len;
1162 int i;
1163 char bufstr[256];
1164 WCHAR bufstrW[MAX_PATH];
1165 BOOL ret = FALSE;
1167 TRACE("(%p/%p, %s, %p, %p)\n", pcs, pcs->handle, debugstr_w(main_name), cb,
1168 user);
1170 if (!pcs->dbg_hdr_addr ||
1171 !ReadProcessMemory(pcs->handle, (void*)pcs->dbg_hdr_addr,
1172 &image_infos, sizeof(image_infos), NULL) ||
1173 !image_infos.infoArray)
1174 goto done;
1175 TRACE("Process has %u image infos at %p\n", image_infos.infoArrayCount, image_infos.infoArray);
1177 len = image_infos.infoArrayCount * sizeof(info_array[0]);
1178 info_array = HeapAlloc(GetProcessHeap(), 0, len);
1179 if (!info_array ||
1180 !ReadProcessMemory(pcs->handle, image_infos.infoArray,
1181 info_array, len, NULL))
1182 goto done;
1183 TRACE("... read image infos\n");
1185 for (i = 0; i < image_infos.infoArrayCount; i++)
1187 if (info_array[i].imageFilePath != NULL &&
1188 ReadProcessMemory(pcs->handle, info_array[i].imageFilePath, bufstr, sizeof(bufstr), NULL))
1190 bufstr[sizeof(bufstr) - 1] = '\0';
1191 TRACE("[%d] image file %s\n", i, debugstr_a(bufstr));
1192 MultiByteToWideChar(CP_UNIXCP, 0, bufstr, -1, bufstrW, sizeof(bufstrW) / sizeof(WCHAR));
1193 if (main_name && !bufstrW[0]) strcpyW(bufstrW, main_name);
1194 if (!cb(bufstrW, (unsigned long)info_array[i].imageLoadAddress, user)) break;
1198 ret = TRUE;
1199 done:
1200 HeapFree(GetProcessHeap(), 0, info_array);
1201 return ret;
1204 struct macho_sync
1206 struct process* pcs;
1207 struct macho_info macho_info;
1210 static BOOL macho_enum_sync_cb(const WCHAR* name, unsigned long addr, void* user)
1212 struct macho_sync* ms = user;
1214 TRACE("(%s, 0x%08lx, %p)\n", debugstr_w(name), addr, user);
1215 macho_search_and_load_file(ms->pcs, name, addr, &ms->macho_info);
1216 return TRUE;
1219 /******************************************************************
1220 * macho_synchronize_module_list
1222 * Rescans the debuggee's modules list and synchronizes it with
1223 * the one from 'pcs', ie:
1224 * - if a module is in debuggee and not in pcs, it's loaded into pcs
1225 * - if a module is in pcs and not in debuggee, it's unloaded from pcs
1227 BOOL macho_synchronize_module_list(struct process* pcs)
1229 struct module* module;
1230 struct macho_sync ms;
1232 TRACE("(%p/%p)\n", pcs, pcs->handle);
1234 for (module = pcs->lmodules; module; module = module->next)
1236 if (module->type == DMT_MACHO && !module->is_virtual)
1237 module->macho_info->in_use = 0;
1240 ms.pcs = pcs;
1241 ms.macho_info.flags = MACHO_INFO_MODULE;
1242 if (!macho_enum_modules_internal(pcs, NULL, macho_enum_sync_cb, &ms))
1243 return FALSE;
1245 module = pcs->lmodules;
1246 while (module)
1248 if (module->type == DMT_MACHO && !module->is_virtual &&
1249 !module->macho_info->in_use && !module->macho_info->is_loader)
1251 module_remove(pcs, module);
1252 /* restart all over */
1253 module = pcs->lmodules;
1255 else module = module->next;
1257 return TRUE;
1260 /******************************************************************
1261 * macho_search_loader
1263 * Lookup in a running Mach-O process the loader, and sets its Mach-O link
1264 * address (for accessing the list of loaded images) in pcs.
1265 * If flags is MACHO_INFO_MODULE, the module for the loader is also
1266 * added as a module into pcs.
1268 static BOOL macho_search_loader(struct process* pcs, struct macho_info* macho_info)
1270 BOOL ret;
1271 const char* ptr;
1273 TRACE("(%p/%p, %p)\n", pcs, pcs->handle, macho_info);
1275 /* All binaries are loaded with WINELOADER (if run from tree) or by the
1276 * main executable
1278 if ((ptr = getenv("WINELOADER")))
1280 WCHAR tmp[MAX_PATH];
1281 MultiByteToWideChar(CP_UNIXCP, 0, ptr, -1, tmp, sizeof(tmp) / sizeof(WCHAR));
1282 ret = macho_search_and_load_file(pcs, tmp, 0, macho_info);
1284 else
1286 ret = macho_search_and_load_file(pcs, S_WineW, 0, macho_info);
1288 return ret;
1291 /******************************************************************
1292 * macho_read_wine_loader_dbg_info
1294 * Try to find a decent wine executable which could have loaded the debuggee
1296 BOOL macho_read_wine_loader_dbg_info(struct process* pcs)
1298 struct macho_info macho_info;
1300 TRACE("(%p/%p)\n", pcs, pcs->handle);
1301 macho_info.flags = MACHO_INFO_DEBUG_HEADER | MACHO_INFO_MODULE;
1302 if (!macho_search_loader(pcs, &macho_info)) return FALSE;
1303 macho_info.module->macho_info->is_loader = 1;
1304 module_set_module(macho_info.module, S_WineLoaderW);
1305 return (pcs->dbg_hdr_addr = macho_info.dbg_hdr_addr) != 0;
1308 /******************************************************************
1309 * macho_enum_modules
1311 * Enumerates the Mach-O loaded modules from a running target (hProc)
1312 * This function doesn't require that someone has called SymInitialize
1313 * on this very process.
1315 BOOL macho_enum_modules(HANDLE hProc, enum_modules_cb cb, void* user)
1317 struct process pcs;
1318 struct macho_info macho_info;
1319 BOOL ret;
1321 TRACE("(%p, %p, %p)\n", hProc, cb, user);
1322 memset(&pcs, 0, sizeof(pcs));
1323 pcs.handle = hProc;
1324 macho_info.flags = MACHO_INFO_DEBUG_HEADER | MACHO_INFO_NAME;
1325 if (!macho_search_loader(&pcs, &macho_info)) return FALSE;
1326 pcs.dbg_hdr_addr = macho_info.dbg_hdr_addr;
1327 ret = macho_enum_modules_internal(&pcs, macho_info.module_name, cb, user);
1328 HeapFree(GetProcessHeap(), 0, (char*)macho_info.module_name);
1329 return ret;
1332 struct macho_load
1334 struct process* pcs;
1335 struct macho_info macho_info;
1336 const WCHAR* name;
1337 BOOL ret;
1340 /******************************************************************
1341 * macho_load_cb
1343 * Callback for macho_load_module, used to walk the list of loaded
1344 * modules.
1346 static BOOL macho_load_cb(const WCHAR* name, unsigned long addr, void* user)
1348 struct macho_load* ml = user;
1349 const WCHAR* p;
1351 TRACE("(%s, 0x%08lx, %p)\n", debugstr_w(name), addr, user);
1353 /* memcmp is needed for matches when bufstr contains also version information
1354 * ml->name: libc.so, name: libc.so.6.0
1356 p = strrchrW(name, '/');
1357 if (!p++) p = name;
1358 if (!memcmp(p, ml->name, lstrlenW(ml->name) * sizeof(WCHAR)))
1360 ml->ret = macho_search_and_load_file(ml->pcs, name, addr, &ml->macho_info);
1361 return FALSE;
1363 return TRUE;
1366 /******************************************************************
1367 * macho_load_module
1369 * Loads a Mach-O module and stores it in process' module list.
1370 * Also, find module real name and load address from
1371 * the real loaded modules list in pcs address space.
1373 struct module* macho_load_module(struct process* pcs, const WCHAR* name, unsigned long addr)
1375 struct macho_load ml;
1377 TRACE("(%p/%p, %s, 0x%08lx)\n", pcs, pcs->handle, debugstr_w(name), addr);
1379 ml.macho_info.flags = MACHO_INFO_MODULE;
1380 ml.ret = FALSE;
1382 if (pcs->dbg_hdr_addr) /* we're debugging a live target */
1384 ml.pcs = pcs;
1385 /* do only the lookup from the filename, not the path (as we lookup module
1386 * name in the process' loaded module list)
1388 ml.name = strrchrW(name, '/');
1389 if (!ml.name++) ml.name = name;
1390 ml.ret = FALSE;
1392 if (!macho_enum_modules_internal(pcs, NULL, macho_load_cb, &ml))
1393 return NULL;
1395 else if (addr)
1397 ml.name = name;
1398 ml.ret = macho_search_and_load_file(pcs, ml.name, addr, &ml.macho_info);
1400 if (!ml.ret) return NULL;
1401 assert(ml.macho_info.module);
1402 return ml.macho_info.module;
1405 #else /* !__MACH__ */
1407 BOOL macho_synchronize_module_list(struct process* pcs)
1409 return FALSE;
1412 BOOL macho_fetch_file_info(const WCHAR* name, DWORD* base,
1413 DWORD* size, DWORD* checksum)
1415 return FALSE;
1418 BOOL macho_read_wine_loader_dbg_info(struct process* pcs)
1420 return FALSE;
1423 BOOL macho_enum_modules(HANDLE hProc, enum_modules_cb cb, void* user)
1425 return FALSE;
1428 struct module* macho_load_module(struct process* pcs, const WCHAR* name, unsigned long addr)
1430 return NULL;
1433 BOOL macho_load_debug_info(struct module* module, struct macho_file_map* fmap)
1435 return FALSE;
1437 #endif /* __MACH__ */