dbghelp: Parse the DWARF information in Mach-O modules.
[wine.git] / dlls / dbghelp / macho_module.c
blobf39b4b6b97f6b7f5861aabeaef287bd2121c8fd8
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 <assert.h>
28 #include <stdarg.h>
29 #include <errno.h>
30 #ifdef HAVE_SYS_STAT_H
31 # include <sys/stat.h>
32 #endif
33 #ifdef HAVE_SYS_MMAN_H
34 # include <sys/mman.h>
35 #endif
37 #include "ntstatus.h"
38 #define WIN32_NO_STATUS
39 #include "dbghelp_private.h"
40 #include "winternl.h"
41 #include "wine/library.h"
42 #include "wine/debug.h"
43 #include "image_private.h"
45 #ifdef HAVE_MACH_O_LOADER_H
47 #include <mach-o/fat.h>
48 #include <mach-o/loader.h>
49 #include <mach-o/nlist.h>
51 #ifdef HAVE_MACH_O_DYLD_IMAGES_H
52 #include <mach-o/dyld_images.h>
53 #else
54 struct dyld_image_info {
55 const struct mach_header *imageLoadAddress;
56 const char *imageFilePath;
57 uintptr_t imageFileModDate;
60 struct dyld_all_image_infos {
61 uint32_t version;
62 uint32_t infoArrayCount;
63 const struct dyld_image_info *infoArray;
64 void* notification;
65 int processDetachedFromSharedRegion;
67 #endif
69 #ifdef WORDS_BIGENDIAN
70 #define swap_ulong_be_to_host(n) (n)
71 #else
72 #define swap_ulong_be_to_host(n) (RtlUlongByteSwap(n))
73 #endif
75 WINE_DEFAULT_DEBUG_CHANNEL(dbghelp_macho);
78 #ifdef _WIN64
79 typedef struct segment_command_64 macho_segment_command;
80 typedef struct nlist_64 macho_nlist;
82 #define TARGET_CPU_TYPE CPU_TYPE_X86_64
83 #define TARGET_MH_MAGIC MH_MAGIC_64
84 #define TARGET_SEGMENT_COMMAND LC_SEGMENT_64
85 #else
86 typedef struct segment_command macho_segment_command;
87 typedef struct nlist macho_nlist;
89 #define TARGET_CPU_TYPE CPU_TYPE_X86
90 #define TARGET_MH_MAGIC MH_MAGIC
91 #define TARGET_SEGMENT_COMMAND LC_SEGMENT
92 #endif
95 struct macho_module_info
97 struct image_file_map file_map;
98 unsigned long load_addr;
99 unsigned short in_use : 1,
100 is_loader : 1;
103 #define MACHO_INFO_DEBUG_HEADER 0x0001
104 #define MACHO_INFO_MODULE 0x0002
105 #define MACHO_INFO_NAME 0x0004
107 struct macho_info
109 unsigned flags; /* IN one (or several) of the MACHO_INFO constants */
110 unsigned long dbg_hdr_addr; /* OUT address of debug header (if MACHO_INFO_DEBUG_HEADER is set) */
111 struct module* module; /* OUT loaded module (if MACHO_INFO_MODULE is set) */
112 const WCHAR* module_name; /* OUT found module name (if MACHO_INFO_NAME is set) */
115 static void macho_unmap_file(struct image_file_map* fmap);
117 /******************************************************************
118 * macho_calc_range
120 * For a range (offset & length) of a single architecture within
121 * a Mach-O file, calculate the page-aligned range of the whole file
122 * that encompasses it. For a fat binary, the architecture will
123 * itself be offset within the file, so take that into account.
125 static void macho_calc_range(const struct macho_file_map* fmap, unsigned long offset,
126 unsigned long len, unsigned long* out_aligned_offset,
127 unsigned long* out_aligned_end, unsigned long* out_aligned_len,
128 unsigned long* out_misalign)
130 unsigned long pagemask = sysconf( _SC_PAGESIZE ) - 1;
131 unsigned long file_offset, misalign;
133 file_offset = fmap->arch_offset + offset;
134 misalign = file_offset & pagemask;
135 *out_aligned_offset = file_offset - misalign;
136 *out_aligned_end = (file_offset + len + pagemask) & ~pagemask;
137 if (out_aligned_len)
138 *out_aligned_len = *out_aligned_end - *out_aligned_offset;
139 if (out_misalign)
140 *out_misalign = misalign;
143 /******************************************************************
144 * macho_map_range
146 * Maps a range (offset, length in bytes) from a Mach-O file into memory
148 static const char* macho_map_range(const struct macho_file_map* fmap, unsigned long offset, unsigned long len,
149 const char** base)
151 unsigned long misalign, aligned_offset, aligned_map_end, map_size;
152 const void* aligned_ptr;
154 TRACE("(%p/%d, 0x%08lx, 0x%08lx)\n", fmap, fmap->fd, offset, len);
156 macho_calc_range(fmap, offset, len, &aligned_offset, &aligned_map_end,
157 &map_size, &misalign);
159 aligned_ptr = mmap(NULL, map_size, PROT_READ, MAP_PRIVATE, fmap->fd, aligned_offset);
161 TRACE("Mapped (0x%08lx - 0x%08lx) to %p\n", aligned_offset, aligned_map_end, aligned_ptr);
163 if (aligned_ptr == MAP_FAILED) return IMAGE_NO_MAP;
164 if (base)
165 *base = aligned_ptr;
166 return (const char*)aligned_ptr + misalign;
169 /******************************************************************
170 * macho_unmap_range
172 * Unmaps a range (offset, length in bytes) of a Mach-O file from memory
174 static void macho_unmap_range(const char** base, const void** mapped, const struct macho_file_map* fmap,
175 unsigned long offset, unsigned long len)
177 TRACE("(%p, %p, %p/%d, 0x%08lx, 0x%08lx)\n", base, mapped, fmap, fmap->fd, offset, len);
179 if ((mapped && *mapped != IMAGE_NO_MAP) || (base && *base != IMAGE_NO_MAP))
181 unsigned long misalign, aligned_offset, aligned_map_end, map_size;
182 void* aligned_ptr;
184 macho_calc_range(fmap, offset, len, &aligned_offset, &aligned_map_end,
185 &map_size, &misalign);
187 if (mapped)
188 aligned_ptr = (char*)*mapped - misalign;
189 else
190 aligned_ptr = (void*)*base;
191 if (munmap(aligned_ptr, map_size) < 0)
192 WARN("Couldn't unmap the range\n");
193 TRACE("Unmapped (0x%08lx - 0x%08lx) from %p - %p\n", aligned_offset, aligned_map_end, aligned_ptr, (char*)aligned_ptr + map_size);
194 if (mapped)
195 *mapped = IMAGE_NO_MAP;
196 if (base)
197 *base = IMAGE_NO_MAP;
201 /******************************************************************
202 * macho_map_ranges
204 * Maps two ranges (offset, length in bytes) from a Mach-O file
205 * into memory. If the two ranges overlap, use one mmap so that
206 * the munmap doesn't fragment the mapping.
208 static BOOL macho_map_ranges(const struct macho_file_map* fmap,
209 unsigned long offset1, unsigned long len1,
210 unsigned long offset2, unsigned long len2,
211 const void** mapped1, const void** mapped2)
213 unsigned long aligned_offset1, aligned_map_end1;
214 unsigned long aligned_offset2, aligned_map_end2;
216 TRACE("(%p/%d, 0x%08lx, 0x%08lx, 0x%08lx, 0x%08lx, %p, %p)\n", fmap, fmap->fd,
217 offset1, len1, offset2, len2, mapped1, mapped2);
219 macho_calc_range(fmap, offset1, len1, &aligned_offset1, &aligned_map_end1, NULL, NULL);
220 macho_calc_range(fmap, offset2, len2, &aligned_offset2, &aligned_map_end2, NULL, NULL);
222 if (aligned_map_end1 < aligned_offset2 || aligned_map_end2 < aligned_offset1)
224 *mapped1 = macho_map_range(fmap, offset1, len1, NULL);
225 if (*mapped1 != IMAGE_NO_MAP)
227 *mapped2 = macho_map_range(fmap, offset2, len2, NULL);
228 if (*mapped2 == IMAGE_NO_MAP)
229 macho_unmap_range(NULL, mapped1, fmap, offset1, len1);
232 else
234 if (offset1 < offset2)
236 *mapped1 = macho_map_range(fmap, offset1, offset2 + len2 - offset1, NULL);
237 if (*mapped1 != IMAGE_NO_MAP)
238 *mapped2 = (const char*)*mapped1 + offset2 - offset1;
240 else
242 *mapped2 = macho_map_range(fmap, offset2, offset1 + len1 - offset2, NULL);
243 if (*mapped2 != IMAGE_NO_MAP)
244 *mapped1 = (const char*)*mapped2 + offset1 - offset2;
248 TRACE(" => %p, %p\n", *mapped1, *mapped2);
250 return (*mapped1 != IMAGE_NO_MAP) && (*mapped2 != IMAGE_NO_MAP);
253 /******************************************************************
254 * macho_unmap_ranges
256 * Unmaps two ranges (offset, length in bytes) of a Mach-O file
257 * from memory. Use for ranges which were mapped by
258 * macho_map_ranges.
260 static void macho_unmap_ranges(const struct macho_file_map* fmap,
261 unsigned long offset1, unsigned long len1,
262 unsigned long offset2, unsigned long len2,
263 const void** mapped1, const void** mapped2)
265 unsigned long aligned_offset1, aligned_map_end1;
266 unsigned long aligned_offset2, aligned_map_end2;
268 TRACE("(%p/%d, 0x%08lx, 0x%08lx, 0x%08lx, 0x%08lx, %p/%p, %p/%p)\n", fmap, fmap->fd,
269 offset1, len1, offset2, len2, mapped1, *mapped1, mapped2, *mapped2);
271 macho_calc_range(fmap, offset1, len1, &aligned_offset1, &aligned_map_end1, NULL, NULL);
272 macho_calc_range(fmap, offset2, len2, &aligned_offset2, &aligned_map_end2, NULL, NULL);
274 if (aligned_map_end1 < aligned_offset2 || aligned_map_end2 < aligned_offset1)
276 macho_unmap_range(NULL, mapped1, fmap, offset1, len1);
277 macho_unmap_range(NULL, mapped2, fmap, offset2, len2);
279 else
281 if (offset1 < offset2)
283 macho_unmap_range(NULL, mapped1, fmap, offset1, offset2 + len2 - offset1);
284 *mapped2 = IMAGE_NO_MAP;
286 else
288 macho_unmap_range(NULL, mapped2, fmap, offset2, offset1 + len1 - offset2);
289 *mapped1 = IMAGE_NO_MAP;
294 /******************************************************************
295 * macho_find_section
297 BOOL macho_find_section(struct image_file_map* ifm, const char* segname, const char* sectname, struct image_section_map* ism)
299 struct macho_file_map* fmap;
300 unsigned i;
301 char tmp[sizeof(fmap->sect[0].section->sectname)];
303 /* Other parts of dbghelp use section names like ".eh_frame". Mach-O uses
304 names like "__eh_frame". Convert those. */
305 if (sectname[0] == '.')
307 lstrcpynA(tmp, "__", sizeof(tmp));
308 lstrcpynA(tmp + 2, sectname + 1, sizeof(tmp) - 2);
309 sectname = tmp;
312 fmap = &ifm->u.macho;
313 for (i = 0; i < fmap->num_sections; i++)
315 if (strcmp(fmap->sect[i].section->sectname, sectname) == 0 &&
316 (!segname || strcmp(fmap->sect[i].section->sectname, segname) == 0))
318 ism->fmap = ifm;
319 ism->sidx = i;
320 return TRUE;
324 ism->fmap = NULL;
325 ism->sidx = -1;
326 return FALSE;
329 /******************************************************************
330 * macho_map_section
332 const char* macho_map_section(struct image_section_map* ism)
334 struct macho_file_map* fmap = &ism->fmap->u.macho;
336 assert(ism->fmap->modtype == DMT_MACHO);
337 if (ism->sidx < 0 || ism->sidx >= ism->fmap->u.macho.num_sections)
338 return IMAGE_NO_MAP;
340 return macho_map_range(fmap, fmap->sect[ism->sidx].section->offset, fmap->sect[ism->sidx].section->size,
341 &fmap->sect[ism->sidx].mapped);
344 /******************************************************************
345 * macho_unmap_section
347 void macho_unmap_section(struct image_section_map* ism)
349 struct macho_file_map* fmap = &ism->fmap->u.macho;
351 if (ism->sidx >= 0 && ism->sidx < fmap->num_sections && fmap->sect[ism->sidx].mapped != IMAGE_NO_MAP)
353 macho_unmap_range(&fmap->sect[ism->sidx].mapped, NULL, fmap, fmap->sect[ism->sidx].section->offset,
354 fmap->sect[ism->sidx].section->size);
358 /******************************************************************
359 * macho_get_map_rva
361 DWORD_PTR macho_get_map_rva(const struct image_section_map* ism)
363 if (ism->sidx < 0 || ism->sidx >= ism->fmap->u.macho.num_sections)
364 return 0;
365 return ism->fmap->u.macho.sect[ism->sidx].section->addr - ism->fmap->u.macho.segs_start;
368 /******************************************************************
369 * macho_get_map_size
371 unsigned macho_get_map_size(const struct image_section_map* ism)
373 if (ism->sidx < 0 || ism->sidx >= ism->fmap->u.macho.num_sections)
374 return 0;
375 return ism->fmap->u.macho.sect[ism->sidx].section->size;
378 /******************************************************************
379 * macho_map_load_commands
381 * Maps the load commands from a Mach-O file into memory
383 static const struct load_command* macho_map_load_commands(struct macho_file_map* fmap)
385 if (fmap->load_commands == IMAGE_NO_MAP)
387 fmap->load_commands = (const struct load_command*) macho_map_range(
388 fmap, sizeof(fmap->mach_header), fmap->mach_header.sizeofcmds, NULL);
389 TRACE("Mapped load commands: %p\n", fmap->load_commands);
392 return fmap->load_commands;
395 /******************************************************************
396 * macho_unmap_load_commands
398 * Unmaps the load commands of a Mach-O file from memory
400 static void macho_unmap_load_commands(struct macho_file_map* fmap)
402 if (fmap->load_commands != IMAGE_NO_MAP)
404 TRACE("Unmapping load commands: %p\n", fmap->load_commands);
405 macho_unmap_range(NULL, (const void**)&fmap->load_commands, fmap,
406 sizeof(fmap->mach_header), fmap->mach_header.sizeofcmds);
410 /******************************************************************
411 * macho_next_load_command
413 * Advance to the next load command
415 static const struct load_command* macho_next_load_command(const struct load_command* lc)
417 return (const struct load_command*)((const char*)lc + lc->cmdsize);
420 /******************************************************************
421 * macho_enum_load_commands
423 * Enumerates the load commands for a Mach-O file, selecting by
424 * the command type, calling a callback for each. If the callback
425 * returns <0, that indicates an error. If it returns >0, that means
426 * it's not interested in getting any more load commands.
427 * If this function returns <0, that's an error produced by the
428 * callback. If >=0, that's the count of load commands successfully
429 * processed.
431 static int macho_enum_load_commands(struct macho_file_map* fmap, unsigned cmd,
432 int (*cb)(struct macho_file_map*, const struct load_command*, void*),
433 void* user)
435 const struct load_command* lc;
436 int i;
437 int count = 0;
439 TRACE("(%p/%d, %u, %p, %p)\n", fmap, fmap->fd, cmd, cb, user);
441 if ((lc = macho_map_load_commands(fmap)) == IMAGE_NO_MAP) return -1;
443 TRACE("%d total commands\n", fmap->mach_header.ncmds);
445 for (i = 0; i < fmap->mach_header.ncmds; i++, lc = macho_next_load_command(lc))
447 int result;
449 if (cmd && cmd != lc->cmd) continue;
450 count++;
452 result = cb(fmap, lc, user);
453 TRACE("load_command[%d] (%p), cmd %u; callback => %d\n", i, lc, lc->cmd, result);
454 if (result) return (result < 0) ? result : count;
457 return count;
460 /******************************************************************
461 * macho_count_sections
463 * Callback for macho_enum_load_commands. Counts the number of
464 * significant sections in a Mach-O file. All commands are
465 * expected to be of LC_SEGMENT[_64] type.
467 static int macho_count_sections(struct macho_file_map* fmap, const struct load_command* lc, void* user)
469 const macho_segment_command* sc = (const macho_segment_command*)lc;
471 TRACE("(%p/%d, %p, %p) segment %s\n", fmap, fmap->fd, lc, user, debugstr_an(sc->segname, sizeof(sc->segname)));
473 fmap->num_sections += sc->nsects;
474 return 0;
477 /******************************************************************
478 * macho_load_section_info
480 * Callback for macho_enum_load_commands. Accumulates the address
481 * range covered by the segments of a Mach-O file and builds the
482 * section map. All commands are expected to be of LC_SEGMENT[_64] type.
484 static int macho_load_section_info(struct macho_file_map* fmap, const struct load_command* lc, void* user)
486 const macho_segment_command* sc = (const macho_segment_command*)lc;
487 int* section_index = (int*)user;
488 const macho_section* section;
489 int i;
490 unsigned long tmp, page_mask = sysconf( _SC_PAGESIZE ) - 1;
492 TRACE("(%p/%d, %p, %p) before: 0x%08lx - 0x%08lx\n", fmap, fmap->fd, lc, user,
493 (unsigned long)fmap->segs_start, (unsigned long)fmap->segs_size);
494 TRACE("Segment command vm: 0x%08lx - 0x%08lx\n", (unsigned long)sc->vmaddr,
495 (unsigned long)(sc->vmaddr + sc->vmsize));
497 if (!strncmp(sc->segname, "WINE_", 5))
498 TRACE("Ignoring special Wine segment %s\n", debugstr_an(sc->segname, sizeof(sc->segname)));
499 else if (!strncmp(sc->segname, "__PAGEZERO", 10))
500 TRACE("Ignoring __PAGEZERO segment\n");
501 else
503 /* If this segment starts before previously-known earliest, record new earliest. */
504 if (sc->vmaddr < fmap->segs_start)
505 fmap->segs_start = sc->vmaddr;
507 /* If this segment extends beyond previously-known furthest, record new furthest. */
508 tmp = (sc->vmaddr + sc->vmsize + page_mask) & ~page_mask;
509 if (fmap->segs_size < tmp) fmap->segs_size = tmp;
511 TRACE("after: 0x%08lx - 0x%08lx\n", (unsigned long)fmap->segs_start, (unsigned long)fmap->segs_size);
514 section = (const macho_section*)(sc + 1);
515 for (i = 0; i < sc->nsects; i++)
517 fmap->sect[*section_index].section = &section[i];
518 fmap->sect[*section_index].mapped = IMAGE_NO_MAP;
519 (*section_index)++;
522 return 0;
525 /******************************************************************
526 * reset_file_map
528 static inline void reset_file_map(struct image_file_map* ifm)
530 struct macho_file_map* fmap = &ifm->u.macho;
532 fmap->fd = -1;
533 fmap->load_commands = IMAGE_NO_MAP;
534 fmap->num_sections = 0;
535 fmap->sect = NULL;
538 /******************************************************************
539 * macho_map_file
541 * Maps a Mach-O file into memory (and checks it's a real Mach-O file)
543 static BOOL macho_map_file(const WCHAR* filenameW, struct image_file_map* ifm)
545 struct macho_file_map* fmap = &ifm->u.macho;
546 struct fat_header fat_header;
547 struct stat statbuf;
548 int i;
549 char* filename;
550 unsigned len;
551 BOOL ret = FALSE;
553 TRACE("(%s, %p)\n", debugstr_w(filenameW), fmap);
555 reset_file_map(ifm);
557 ifm->modtype = DMT_MACHO;
558 #ifdef _WIN64
559 ifm->addr_size = 64;
560 #else
561 ifm->addr_size = 32;
562 #endif
564 len = WideCharToMultiByte(CP_UNIXCP, 0, filenameW, -1, NULL, 0, NULL, NULL);
565 if (!(filename = HeapAlloc(GetProcessHeap(), 0, len)))
567 WARN("failed to allocate filename buffer\n");
568 return FALSE;
570 WideCharToMultiByte(CP_UNIXCP, 0, filenameW, -1, filename, len, NULL, NULL);
572 /* check that the file exists */
573 if (stat(filename, &statbuf) == -1 || S_ISDIR(statbuf.st_mode))
575 TRACE("stat() failed or %s is directory: %s\n", debugstr_a(filename), strerror(errno));
576 goto done;
579 /* Now open the file, so that we can mmap() it. */
580 if ((fmap->fd = open(filename, O_RDONLY)) == -1)
582 TRACE("failed to open file %s: %d\n", debugstr_a(filename), errno);
583 goto done;
586 if (read(fmap->fd, &fat_header, sizeof(fat_header)) != sizeof(fat_header))
588 TRACE("failed to read fat header: %d\n", errno);
589 goto done;
591 TRACE("... got possible fat header\n");
593 /* Fat header is always in big-endian order. */
594 if (swap_ulong_be_to_host(fat_header.magic) == FAT_MAGIC)
596 int narch = swap_ulong_be_to_host(fat_header.nfat_arch);
597 for (i = 0; i < narch; i++)
599 struct fat_arch fat_arch;
600 if (read(fmap->fd, &fat_arch, sizeof(fat_arch)) != sizeof(fat_arch))
601 goto done;
602 if (swap_ulong_be_to_host(fat_arch.cputype) == TARGET_CPU_TYPE)
604 fmap->arch_offset = swap_ulong_be_to_host(fat_arch.offset);
605 break;
608 if (i >= narch) goto done;
609 TRACE("... found target arch (%d)\n", TARGET_CPU_TYPE);
611 else
613 fmap->arch_offset = 0;
614 TRACE("... not a fat header\n");
617 /* Individual architecture (standalone or within a fat file) is in its native byte order. */
618 lseek(fmap->fd, fmap->arch_offset, SEEK_SET);
619 if (read(fmap->fd, &fmap->mach_header, sizeof(fmap->mach_header)) != sizeof(fmap->mach_header))
620 goto done;
621 TRACE("... got possible Mach header\n");
622 /* and check for a Mach-O header */
623 if (fmap->mach_header.magic != TARGET_MH_MAGIC ||
624 fmap->mach_header.cputype != TARGET_CPU_TYPE) goto done;
625 /* Make sure the file type is one of the ones we expect. */
626 switch (fmap->mach_header.filetype)
628 case MH_EXECUTE:
629 case MH_DYLIB:
630 case MH_DYLINKER:
631 case MH_BUNDLE:
632 break;
633 default:
634 goto done;
636 TRACE("... verified Mach header\n");
638 fmap->num_sections = 0;
639 if (macho_enum_load_commands(fmap, TARGET_SEGMENT_COMMAND, macho_count_sections, NULL) < 0)
640 goto done;
641 TRACE("%d sections\n", fmap->num_sections);
643 fmap->sect = HeapAlloc(GetProcessHeap(), 0, fmap->num_sections * sizeof(fmap->sect[0]));
644 if (!fmap->sect)
645 goto done;
647 fmap->segs_size = 0;
648 fmap->segs_start = ~0L;
650 i = 0;
651 if (macho_enum_load_commands(fmap, TARGET_SEGMENT_COMMAND, macho_load_section_info, &i) < 0)
653 fmap->num_sections = 0;
654 goto done;
657 fmap->segs_size -= fmap->segs_start;
658 TRACE("segs_start: 0x%08lx, segs_size: 0x%08lx\n", (unsigned long)fmap->segs_start,
659 (unsigned long)fmap->segs_size);
661 ret = TRUE;
662 done:
663 if (!ret)
664 macho_unmap_file(ifm);
665 HeapFree(GetProcessHeap(), 0, filename);
666 return ret;
669 /******************************************************************
670 * macho_unmap_file
672 * Unmaps a Mach-O file from memory (previously mapped with macho_map_file)
674 static void macho_unmap_file(struct image_file_map* ifm)
676 TRACE("(%p/%d)\n", ifm, ifm->u.macho.fd);
677 if (ifm->u.macho.fd != -1)
679 struct image_section_map ism;
681 ism.fmap = ifm;
682 for (ism.sidx = 0; ism.sidx < ifm->u.macho.num_sections; ism.sidx++)
683 macho_unmap_section(&ism);
685 HeapFree(GetProcessHeap(), 0, ifm->u.macho.sect);
686 macho_unmap_load_commands(&ifm->u.macho);
687 close(ifm->u.macho.fd);
688 ifm->u.macho.fd = -1;
692 /******************************************************************
693 * macho_sect_is_code
695 * Checks if a section, identified by sectidx which is a 1-based
696 * index into the sections of all segments, in order of load
697 * commands, contains code.
699 static BOOL macho_sect_is_code(struct macho_file_map* fmap, unsigned char sectidx)
701 BOOL ret;
703 TRACE("(%p/%d, %u)\n", fmap, fmap->fd, sectidx);
705 if (!sectidx) return FALSE;
707 sectidx--; /* convert from 1-based to 0-based */
708 if (sectidx >= fmap->num_sections) return FALSE;
710 ret = (!(fmap->sect[sectidx].section->flags & SECTION_TYPE) &&
711 (fmap->sect[sectidx].section->flags & (S_ATTR_PURE_INSTRUCTIONS|S_ATTR_SOME_INSTRUCTIONS)));
712 TRACE("-> %d\n", ret);
713 return ret;
716 struct symtab_elt
718 struct hash_table_elt ht_elt;
719 struct symt_compiland* compiland;
720 unsigned long addr;
721 unsigned char is_code:1,
722 is_public:1,
723 is_global:1,
724 used:1;
727 struct macho_debug_info
729 struct macho_file_map* fmap;
730 struct module* module;
731 struct pool pool;
732 struct hash_table ht_symtab;
735 /******************************************************************
736 * macho_stabs_def_cb
738 * Callback for stabs_parse. Collect symbol definitions.
740 static void macho_stabs_def_cb(struct module* module, unsigned long load_offset,
741 const char* name, unsigned long offset,
742 BOOL is_public, BOOL is_global, unsigned char sectidx,
743 struct symt_compiland* compiland, void* user)
745 struct macho_debug_info* mdi = user;
746 struct symtab_elt* ste;
748 TRACE("(%p, 0x%08lx, %s, 0x%08lx, %d, %d, %u, %p, %p/%p/%d)\n", module, load_offset,
749 debugstr_a(name), offset, is_public, is_global, sectidx,
750 compiland, mdi, mdi->fmap, mdi->fmap->fd);
752 /* Defer the creation of new non-debugging symbols until after we've
753 * finished parsing the stabs. */
754 ste = pool_alloc(&mdi->pool, sizeof(*ste));
755 ste->ht_elt.name = pool_strdup(&mdi->pool, name);
756 ste->compiland = compiland;
757 ste->addr = load_offset + offset;
758 ste->is_code = !!macho_sect_is_code(mdi->fmap, sectidx);
759 ste->is_public = !!is_public;
760 ste->is_global = !!is_global;
761 ste->used = 0;
762 hash_table_add(&mdi->ht_symtab, &ste->ht_elt);
765 /******************************************************************
766 * macho_parse_symtab
768 * Callback for macho_enum_load_commands. Processes the LC_SYMTAB
769 * load commands from the Mach-O file.
771 static int macho_parse_symtab(struct macho_file_map* fmap,
772 const struct load_command* lc, void* user)
774 const struct symtab_command* sc = (const struct symtab_command*)lc;
775 struct macho_debug_info* mdi = user;
776 const macho_nlist* stab;
777 const char* stabstr;
778 int ret = 0;
780 TRACE("(%p/%d, %p, %p) %u syms at 0x%08x, strings 0x%08x - 0x%08x\n", fmap, fmap->fd, lc,
781 user, sc->nsyms, sc->symoff, sc->stroff, sc->stroff + sc->strsize);
783 if (!macho_map_ranges(fmap, sc->symoff, sc->nsyms * sizeof(macho_nlist),
784 sc->stroff, sc->strsize, (const void**)&stab, (const void**)&stabstr))
785 return 0;
787 if (!stabs_parse(mdi->module,
788 mdi->module->format_info[DFI_MACHO]->u.macho_info->load_addr - fmap->segs_start,
789 stab, sc->nsyms * sizeof(macho_nlist),
790 stabstr, sc->strsize, macho_stabs_def_cb, mdi))
791 ret = -1;
793 macho_unmap_ranges(fmap, sc->symoff, sc->nsyms * sizeof(macho_nlist),
794 sc->stroff, sc->strsize, (const void**)&stab, (const void**)&stabstr);
796 return ret;
799 /******************************************************************
800 * macho_finish_stabs
802 * Integrate the non-debugging symbols we've gathered into the
803 * symbols that were generated during stabs parsing.
805 static void macho_finish_stabs(struct module* module, struct hash_table* ht_symtab)
807 struct hash_table_iter hti_ours;
808 struct symtab_elt* ste;
809 BOOL adjusted = FALSE;
811 TRACE("(%p, %p)\n", module, ht_symtab);
813 /* For each of our non-debugging symbols, see if it can provide some
814 * missing details to one of the module's known symbols. */
815 hash_table_iter_init(ht_symtab, &hti_ours, NULL);
816 while ((ste = hash_table_iter_up(&hti_ours)))
818 struct hash_table_iter hti_modules;
819 void* ptr;
820 struct symt_ht* sym;
821 struct symt_function* func;
822 struct symt_data* data;
824 hash_table_iter_init(&module->ht_symbols, &hti_modules, ste->ht_elt.name);
825 while ((ptr = hash_table_iter_up(&hti_modules)))
827 sym = GET_ENTRY(ptr, struct symt_ht, hash_elt);
829 if (strcmp(sym->hash_elt.name, ste->ht_elt.name))
830 continue;
832 switch (sym->symt.tag)
834 case SymTagFunction:
835 func = (struct symt_function*)sym;
836 if (func->address == module->format_info[DFI_MACHO]->u.macho_info->load_addr)
838 TRACE("Adjusting function %p/%s!%s from 0x%08lx to 0x%08lx\n", func,
839 debugstr_w(module->module.ModuleName), sym->hash_elt.name,
840 func->address, ste->addr);
841 func->address = ste->addr;
842 adjusted = TRUE;
844 if (func->address == ste->addr)
845 ste->used = 1;
846 break;
847 case SymTagData:
848 data = (struct symt_data*)sym;
849 switch (data->kind)
851 case DataIsGlobal:
852 case DataIsFileStatic:
853 if (data->u.var.offset == module->format_info[DFI_MACHO]->u.macho_info->load_addr)
855 TRACE("Adjusting data symbol %p/%s!%s from 0x%08lx to 0x%08lx\n",
856 data, debugstr_w(module->module.ModuleName), sym->hash_elt.name,
857 data->u.var.offset, ste->addr);
858 data->u.var.offset = ste->addr;
859 adjusted = TRUE;
861 if (data->u.var.offset == ste->addr)
863 enum DataKind new_kind;
865 new_kind = ste->is_global ? DataIsGlobal : DataIsFileStatic;
866 if (data->kind != new_kind)
868 WARN("Changing kind for %p/%s!%s from %d to %d\n", sym,
869 debugstr_w(module->module.ModuleName), sym->hash_elt.name,
870 (int)data->kind, (int)new_kind);
871 data->kind = new_kind;
872 adjusted = TRUE;
874 ste->used = 1;
876 break;
877 default:;
879 break;
880 default:
881 TRACE("Ignoring tag %u\n", sym->symt.tag);
882 break;
887 if (adjusted)
889 /* since we may have changed some addresses, mark the module to be resorted */
890 module->sortlist_valid = FALSE;
893 /* Mark any of our non-debugging symbols which fall on an already-used
894 * address as "used". This allows us to skip them in the next loop,
895 * below. We do this in separate loops because symt_new_* marks the
896 * list as needing sorting and symt_find_nearest sorts if needed,
897 * causing thrashing. */
898 if (!(dbghelp_options & SYMOPT_PUBLICS_ONLY))
900 hash_table_iter_init(ht_symtab, &hti_ours, NULL);
901 while ((ste = hash_table_iter_up(&hti_ours)))
903 struct symt_ht* sym;
904 ULONG64 addr;
906 if (ste->used) continue;
908 sym = symt_find_nearest(module, ste->addr);
909 if (sym)
910 symt_get_address(&sym->symt, &addr);
911 if (sym && ste->addr == addr)
913 ULONG64 size = 0;
914 DWORD kind = -1;
916 ste->used = 1;
918 /* If neither symbol has a correct size (ours never does), we
919 * consider them both to be markers. No warning is needed in
920 * that case.
921 * Also, we check that we don't have two symbols, one local, the other
922 * global, which is legal.
924 symt_get_info(module, &sym->symt, TI_GET_LENGTH, &size);
925 symt_get_info(module, &sym->symt, TI_GET_DATAKIND, &kind);
926 if (size && kind == (ste->is_global ? DataIsGlobal : DataIsFileStatic))
927 FIXME("Duplicate in %s: %s<%08lx> %s<%s-%s>\n",
928 debugstr_w(module->module.ModuleName),
929 ste->ht_elt.name, ste->addr,
930 sym->hash_elt.name,
931 wine_dbgstr_longlong(addr), wine_dbgstr_longlong(size));
936 /* For any of our remaining non-debugging symbols which have no match
937 * among the module's known symbols, add them as new symbols. */
938 hash_table_iter_init(ht_symtab, &hti_ours, NULL);
939 while ((ste = hash_table_iter_up(&hti_ours)))
941 if (!(dbghelp_options & SYMOPT_PUBLICS_ONLY) && !ste->used)
943 if (ste->is_code)
945 symt_new_function(module, ste->compiland, ste->ht_elt.name,
946 ste->addr, 0, NULL);
948 else
950 struct location loc;
952 loc.kind = loc_absolute;
953 loc.reg = 0;
954 loc.offset = ste->addr;
955 symt_new_global_variable(module, ste->compiland, ste->ht_elt.name,
956 !ste->is_global, loc, 0, NULL);
959 ste->used = 1;
962 if (ste->is_public && !(dbghelp_options & SYMOPT_NO_PUBLICS))
964 symt_new_public(module, ste->compiland, ste->ht_elt.name, ste->addr, 0);
969 /******************************************************************
970 * macho_load_debug_info
972 * Loads Mach-O debugging information from the module image file.
974 BOOL macho_load_debug_info(struct module* module)
976 BOOL ret = FALSE;
977 struct macho_debug_info mdi;
978 int result;
979 struct macho_file_map *fmap;
981 if (module->type != DMT_MACHO || !module->format_info[DFI_MACHO]->u.macho_info)
983 ERR("Bad Mach-O module '%s'\n", debugstr_w(module->module.LoadedImageName));
984 return FALSE;
987 fmap = &module->format_info[DFI_MACHO]->u.macho_info->file_map.u.macho;
989 TRACE("(%p, %p/%d)\n", module, fmap, fmap->fd);
991 module->module.SymType = SymExport;
993 mdi.fmap = fmap;
994 mdi.module = module;
995 pool_init(&mdi.pool, 65536);
996 hash_table_init(&mdi.pool, &mdi.ht_symtab, 256);
997 result = macho_enum_load_commands(fmap, LC_SYMTAB, macho_parse_symtab, &mdi);
998 if (result > 0)
999 ret = TRUE;
1000 else if (result < 0)
1001 WARN("Couldn't correctly read stabs\n");
1003 macho_finish_stabs(module, &mdi.ht_symtab);
1005 if (dwarf2_parse(module, module->reloc_delta, NULL /* FIXME: some thunks to deal with ? */,
1006 &module->format_info[DFI_MACHO]->u.macho_info->file_map))
1007 ret = TRUE;
1009 pool_destroy(&mdi.pool);
1010 return ret;
1013 /******************************************************************
1014 * macho_fetch_file_info
1016 * Gathers some more information for a Mach-O module from a given file
1018 BOOL macho_fetch_file_info(const WCHAR* name, DWORD_PTR* base,
1019 DWORD* size, DWORD* checksum)
1021 struct image_file_map fmap;
1023 TRACE("(%s, %p, %p, %p)\n", debugstr_w(name), base, size, checksum);
1025 if (!macho_map_file(name, &fmap)) return FALSE;
1026 if (base) *base = fmap.u.macho.segs_start;
1027 *size = fmap.u.macho.segs_size;
1028 *checksum = calc_crc32(fmap.u.macho.fd);
1029 macho_unmap_file(&fmap);
1030 return TRUE;
1033 /******************************************************************
1034 * macho_module_remove
1036 static void macho_module_remove(struct process* pcs, struct module_format* modfmt)
1038 macho_unmap_file(&modfmt->u.macho_info->file_map);
1039 HeapFree(GetProcessHeap(), 0, modfmt);
1042 /******************************************************************
1043 * macho_load_file
1045 * Loads the information for Mach-O module stored in 'filename'.
1046 * The module has been loaded at 'load_addr' address.
1047 * returns
1048 * FALSE if the file cannot be found/opened or if the file doesn't
1049 * contain symbolic info (or this info cannot be read or parsed)
1050 * TRUE on success
1052 static BOOL macho_load_file(struct process* pcs, const WCHAR* filename,
1053 unsigned long load_addr, struct macho_info* macho_info)
1055 BOOL ret = TRUE;
1056 struct image_file_map fmap;
1058 TRACE("(%p/%p, %s, 0x%08lx, %p/0x%08x)\n", pcs, pcs->handle, debugstr_w(filename),
1059 load_addr, macho_info, macho_info->flags);
1061 if (!macho_map_file(filename, &fmap)) return FALSE;
1063 /* Find the dynamic loader's table of images loaded into the process.
1065 if (macho_info->flags & MACHO_INFO_DEBUG_HEADER)
1067 PROCESS_BASIC_INFORMATION pbi;
1068 NTSTATUS status;
1070 ret = FALSE;
1072 /* Get address of PEB */
1073 status = NtQueryInformationProcess(pcs->handle, ProcessBasicInformation,
1074 &pbi, sizeof(pbi), NULL);
1075 if (status == STATUS_SUCCESS)
1077 ULONG_PTR dyld_image_info;
1079 /* Read dyld image info address from PEB */
1080 if (ReadProcessMemory(pcs->handle, &pbi.PebBaseAddress->Reserved[0],
1081 &dyld_image_info, sizeof(dyld_image_info), NULL))
1083 TRACE("got dyld_image_info 0x%08lx from PEB %p MacDyldImageInfo %p\n",
1084 (unsigned long)dyld_image_info, pbi.PebBaseAddress, &pbi.PebBaseAddress->Reserved);
1085 macho_info->dbg_hdr_addr = dyld_image_info;
1086 ret = TRUE;
1090 #ifndef __LP64__ /* No reading the symtab with nlist(3) in LP64 */
1091 if (!ret)
1093 static void* dyld_all_image_infos_addr;
1095 /* Our next best guess is that dyld was loaded at its base address
1096 and we can find the dyld image infos address by looking up its symbol. */
1097 if (!dyld_all_image_infos_addr)
1099 struct nlist nl[2];
1100 memset(nl, 0, sizeof(nl));
1101 nl[0].n_un.n_name = (char*)"_dyld_all_image_infos";
1102 if (!nlist("/usr/lib/dyld", nl))
1103 dyld_all_image_infos_addr = (void*)nl[0].n_value;
1106 if (dyld_all_image_infos_addr)
1108 TRACE("got dyld_image_info %p from /usr/lib/dyld symbol table\n",
1109 dyld_all_image_infos_addr);
1110 macho_info->dbg_hdr_addr = (unsigned long)dyld_all_image_infos_addr;
1111 ret = TRUE;
1114 #endif
1117 if (macho_info->flags & MACHO_INFO_MODULE)
1119 struct macho_module_info *macho_module_info;
1120 struct module_format* modfmt =
1121 HeapAlloc(GetProcessHeap(), 0, sizeof(struct module_format) + sizeof(struct macho_module_info));
1122 if (!modfmt) goto leave;
1123 if (!load_addr)
1124 load_addr = fmap.u.macho.segs_start;
1125 macho_info->module = module_new(pcs, filename, DMT_MACHO, FALSE, load_addr,
1126 fmap.u.macho.segs_size, 0, calc_crc32(fmap.u.macho.fd));
1127 if (!macho_info->module)
1129 HeapFree(GetProcessHeap(), 0, modfmt);
1130 goto leave;
1132 macho_info->module->reloc_delta = macho_info->module->module.BaseOfImage - fmap.u.macho.segs_start;
1133 macho_module_info = (void*)(modfmt + 1);
1134 macho_info->module->format_info[DFI_MACHO] = modfmt;
1136 modfmt->module = macho_info->module;
1137 modfmt->remove = macho_module_remove;
1138 modfmt->loc_compute = NULL;
1139 modfmt->u.macho_info = macho_module_info;
1141 macho_module_info->load_addr = load_addr;
1143 macho_module_info->file_map = fmap;
1144 reset_file_map(&fmap);
1145 if (dbghelp_options & SYMOPT_DEFERRED_LOADS)
1146 macho_info->module->module.SymType = SymDeferred;
1147 else if (!macho_load_debug_info(macho_info->module))
1148 ret = FALSE;
1150 macho_info->module->format_info[DFI_MACHO]->u.macho_info->in_use = 1;
1151 macho_info->module->format_info[DFI_MACHO]->u.macho_info->is_loader = 0;
1152 TRACE("module = %p\n", macho_info->module);
1155 if (macho_info->flags & MACHO_INFO_NAME)
1157 WCHAR* ptr;
1158 ptr = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(filename) + 1) * sizeof(WCHAR));
1159 if (ptr)
1161 strcpyW(ptr, filename);
1162 macho_info->module_name = ptr;
1164 else ret = FALSE;
1165 TRACE("module_name = %p %s\n", macho_info->module_name, debugstr_w(macho_info->module_name));
1167 leave:
1168 macho_unmap_file(&fmap);
1170 TRACE(" => %d\n", ret);
1171 return ret;
1174 /******************************************************************
1175 * macho_load_file_from_path
1176 * Tries to load a Mach-O file from a set of paths (separated by ':')
1178 static BOOL macho_load_file_from_path(struct process* pcs,
1179 const WCHAR* filename,
1180 unsigned long load_addr,
1181 const char* path,
1182 struct macho_info* macho_info)
1184 BOOL ret = FALSE;
1185 WCHAR *s, *t, *fn;
1186 WCHAR* pathW = NULL;
1187 unsigned len;
1189 TRACE("(%p/%p, %s, 0x%08lx, %s, %p)\n", pcs, pcs->handle, debugstr_w(filename), load_addr,
1190 debugstr_a(path), macho_info);
1192 if (!path) return FALSE;
1194 len = MultiByteToWideChar(CP_UNIXCP, 0, path, -1, NULL, 0);
1195 pathW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1196 if (!pathW) return FALSE;
1197 MultiByteToWideChar(CP_UNIXCP, 0, path, -1, pathW, len);
1199 for (s = pathW; s && *s; s = (t) ? (t+1) : NULL)
1201 t = strchrW(s, ':');
1202 if (t) *t = '\0';
1203 fn = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(filename) + 1 + lstrlenW(s) + 1) * sizeof(WCHAR));
1204 if (!fn) break;
1205 strcpyW(fn, s);
1206 strcatW(fn, S_SlashW);
1207 strcatW(fn, filename);
1208 ret = macho_load_file(pcs, fn, load_addr, macho_info);
1209 HeapFree(GetProcessHeap(), 0, fn);
1210 if (ret) break;
1211 s = (t) ? (t+1) : NULL;
1214 TRACE(" => %d\n", ret);
1215 HeapFree(GetProcessHeap(), 0, pathW);
1216 return ret;
1219 /******************************************************************
1220 * macho_load_file_from_dll_path
1222 * Tries to load a Mach-O file from the dll path
1224 static BOOL macho_load_file_from_dll_path(struct process* pcs,
1225 const WCHAR* filename,
1226 unsigned long load_addr,
1227 struct macho_info* macho_info)
1229 BOOL ret = FALSE;
1230 unsigned int index = 0;
1231 const char *path;
1233 TRACE("(%p/%p, %s, 0x%08lx, %p)\n", pcs, pcs->handle, debugstr_w(filename), load_addr,
1234 macho_info);
1236 while (!ret && (path = wine_dll_enum_load_path( index++ )))
1238 WCHAR *name;
1239 unsigned len;
1241 len = MultiByteToWideChar(CP_UNIXCP, 0, path, -1, NULL, 0);
1243 name = HeapAlloc( GetProcessHeap(), 0,
1244 (len + lstrlenW(filename) + 2) * sizeof(WCHAR) );
1246 if (!name) break;
1247 MultiByteToWideChar(CP_UNIXCP, 0, path, -1, name, len);
1248 strcatW( name, S_SlashW );
1249 strcatW( name, filename );
1250 ret = macho_load_file(pcs, name, load_addr, macho_info);
1251 HeapFree( GetProcessHeap(), 0, name );
1253 TRACE(" => %d\n", ret);
1254 return ret;
1257 /******************************************************************
1258 * macho_search_and_load_file
1260 * Lookup a file in standard Mach-O locations, and if found, load it
1262 static BOOL macho_search_and_load_file(struct process* pcs, const WCHAR* filename,
1263 unsigned long load_addr,
1264 struct macho_info* macho_info)
1266 BOOL ret = FALSE;
1267 struct module* module;
1268 static const WCHAR S_libstdcPPW[] = {'l','i','b','s','t','d','c','+','+','\0'};
1269 const WCHAR* p;
1271 TRACE("(%p/%p, %s, 0x%08lx, %p)\n", pcs, pcs->handle, debugstr_w(filename), load_addr,
1272 macho_info);
1274 if (filename == NULL || *filename == '\0') return FALSE;
1275 if ((module = module_is_already_loaded(pcs, filename)))
1277 macho_info->module = module;
1278 module->format_info[DFI_MACHO]->u.macho_info->in_use = 1;
1279 return module->module.SymType;
1282 if (strstrW(filename, S_libstdcPPW)) return FALSE; /* We know we can't do it */
1284 /* If has no directories, try LD_LIBRARY_PATH first. */
1285 if (!strchrW(filename, '/'))
1287 ret = macho_load_file_from_path(pcs, filename, load_addr,
1288 getenv("PATH"), macho_info);
1290 /* Try DYLD_LIBRARY_PATH, with just the filename (no directories). */
1291 if (!ret)
1293 if ((p = strrchrW(filename, '/'))) p++;
1294 else p = filename;
1295 ret = macho_load_file_from_path(pcs, p, load_addr,
1296 getenv("DYLD_LIBRARY_PATH"), macho_info);
1298 /* Try the path as given. */
1299 if (!ret)
1300 ret = macho_load_file(pcs, filename, load_addr, macho_info);
1301 /* Try DYLD_FALLBACK_LIBRARY_PATH, with just the filename (no directories). */
1302 if (!ret)
1304 ret = macho_load_file_from_path(pcs, p, load_addr,
1305 getenv("DYLD_FALLBACK_LIBRARY_PATH"), macho_info);
1307 if (!ret && !strchrW(filename, '/'))
1308 ret = macho_load_file_from_dll_path(pcs, filename, load_addr, macho_info);
1310 return ret;
1313 /******************************************************************
1314 * macho_enum_modules_internal
1316 * Enumerate Mach-O modules from a running process
1318 static BOOL macho_enum_modules_internal(const struct process* pcs,
1319 const WCHAR* main_name,
1320 enum_modules_cb cb, void* user)
1322 struct dyld_all_image_infos image_infos;
1323 struct dyld_image_info* info_array = NULL;
1324 unsigned long len;
1325 int i;
1326 char bufstr[256];
1327 WCHAR bufstrW[MAX_PATH];
1328 BOOL ret = FALSE;
1330 TRACE("(%p/%p, %s, %p, %p)\n", pcs, pcs->handle, debugstr_w(main_name), cb,
1331 user);
1333 if (!pcs->dbg_hdr_addr ||
1334 !ReadProcessMemory(pcs->handle, (void*)pcs->dbg_hdr_addr,
1335 &image_infos, sizeof(image_infos), NULL) ||
1336 !image_infos.infoArray)
1337 goto done;
1338 TRACE("Process has %u image infos at %p\n", image_infos.infoArrayCount, image_infos.infoArray);
1340 len = image_infos.infoArrayCount * sizeof(info_array[0]);
1341 info_array = HeapAlloc(GetProcessHeap(), 0, len);
1342 if (!info_array ||
1343 !ReadProcessMemory(pcs->handle, image_infos.infoArray,
1344 info_array, len, NULL))
1345 goto done;
1346 TRACE("... read image infos\n");
1348 for (i = 0; i < image_infos.infoArrayCount; i++)
1350 if (info_array[i].imageFilePath != NULL &&
1351 ReadProcessMemory(pcs->handle, info_array[i].imageFilePath, bufstr, sizeof(bufstr), NULL))
1353 bufstr[sizeof(bufstr) - 1] = '\0';
1354 TRACE("[%d] image file %s\n", i, debugstr_a(bufstr));
1355 MultiByteToWideChar(CP_UNIXCP, 0, bufstr, -1, bufstrW, sizeof(bufstrW) / sizeof(WCHAR));
1356 if (main_name && !bufstrW[0]) strcpyW(bufstrW, main_name);
1357 if (!cb(bufstrW, (unsigned long)info_array[i].imageLoadAddress, user)) break;
1361 ret = TRUE;
1362 done:
1363 HeapFree(GetProcessHeap(), 0, info_array);
1364 return ret;
1367 struct macho_sync
1369 struct process* pcs;
1370 struct macho_info macho_info;
1373 static BOOL macho_enum_sync_cb(const WCHAR* name, unsigned long addr, void* user)
1375 struct macho_sync* ms = user;
1377 TRACE("(%s, 0x%08lx, %p)\n", debugstr_w(name), addr, user);
1378 macho_search_and_load_file(ms->pcs, name, addr, &ms->macho_info);
1379 return TRUE;
1382 /******************************************************************
1383 * macho_synchronize_module_list
1385 * Rescans the debuggee's modules list and synchronizes it with
1386 * the one from 'pcs', ie:
1387 * - if a module is in debuggee and not in pcs, it's loaded into pcs
1388 * - if a module is in pcs and not in debuggee, it's unloaded from pcs
1390 BOOL macho_synchronize_module_list(struct process* pcs)
1392 struct module* module;
1393 struct macho_sync ms;
1395 TRACE("(%p/%p)\n", pcs, pcs->handle);
1397 for (module = pcs->lmodules; module; module = module->next)
1399 if (module->type == DMT_MACHO && !module->is_virtual)
1400 module->format_info[DFI_MACHO]->u.macho_info->in_use = 0;
1403 ms.pcs = pcs;
1404 ms.macho_info.flags = MACHO_INFO_MODULE;
1405 if (!macho_enum_modules_internal(pcs, NULL, macho_enum_sync_cb, &ms))
1406 return FALSE;
1408 module = pcs->lmodules;
1409 while (module)
1411 if (module->type == DMT_MACHO && !module->is_virtual &&
1412 !module->format_info[DFI_MACHO]->u.macho_info->in_use &&
1413 !module->format_info[DFI_MACHO]->u.macho_info->is_loader)
1415 module_remove(pcs, module);
1416 /* restart all over */
1417 module = pcs->lmodules;
1419 else module = module->next;
1421 return TRUE;
1424 /******************************************************************
1425 * macho_search_loader
1427 * Lookup in a running Mach-O process the loader, and sets its Mach-O link
1428 * address (for accessing the list of loaded images) in pcs.
1429 * If flags is MACHO_INFO_MODULE, the module for the loader is also
1430 * added as a module into pcs.
1432 static BOOL macho_search_loader(struct process* pcs, struct macho_info* macho_info)
1434 return macho_search_and_load_file(pcs, get_wine_loader_name(), 0, macho_info);
1437 /******************************************************************
1438 * macho_read_wine_loader_dbg_info
1440 * Try to find a decent wine executable which could have loaded the debuggee
1442 BOOL macho_read_wine_loader_dbg_info(struct process* pcs)
1444 struct macho_info macho_info;
1446 TRACE("(%p/%p)\n", pcs, pcs->handle);
1447 macho_info.flags = MACHO_INFO_DEBUG_HEADER | MACHO_INFO_MODULE;
1448 if (!macho_search_loader(pcs, &macho_info)) return FALSE;
1449 macho_info.module->format_info[DFI_MACHO]->u.macho_info->is_loader = 1;
1450 module_set_module(macho_info.module, S_WineLoaderW);
1451 return (pcs->dbg_hdr_addr = macho_info.dbg_hdr_addr) != 0;
1454 /******************************************************************
1455 * macho_enum_modules
1457 * Enumerates the Mach-O loaded modules from a running target (hProc)
1458 * This function doesn't require that someone has called SymInitialize
1459 * on this very process.
1461 BOOL macho_enum_modules(HANDLE hProc, enum_modules_cb cb, void* user)
1463 struct process pcs;
1464 struct macho_info macho_info;
1465 BOOL ret;
1467 TRACE("(%p, %p, %p)\n", hProc, cb, user);
1468 memset(&pcs, 0, sizeof(pcs));
1469 pcs.handle = hProc;
1470 macho_info.flags = MACHO_INFO_DEBUG_HEADER | MACHO_INFO_NAME;
1471 if (!macho_search_loader(&pcs, &macho_info)) return FALSE;
1472 pcs.dbg_hdr_addr = macho_info.dbg_hdr_addr;
1473 ret = macho_enum_modules_internal(&pcs, macho_info.module_name, cb, user);
1474 HeapFree(GetProcessHeap(), 0, (char*)macho_info.module_name);
1475 return ret;
1478 struct macho_load
1480 struct process* pcs;
1481 struct macho_info macho_info;
1482 const WCHAR* name;
1483 BOOL ret;
1486 /******************************************************************
1487 * macho_load_cb
1489 * Callback for macho_load_module, used to walk the list of loaded
1490 * modules.
1492 static BOOL macho_load_cb(const WCHAR* name, unsigned long addr, void* user)
1494 struct macho_load* ml = user;
1495 const WCHAR* p;
1497 TRACE("(%s, 0x%08lx, %p)\n", debugstr_w(name), addr, user);
1499 /* memcmp is needed for matches when bufstr contains also version information
1500 * ml->name: libc.so, name: libc.so.6.0
1502 p = strrchrW(name, '/');
1503 if (!p++) p = name;
1504 if (!memcmp(p, ml->name, lstrlenW(ml->name) * sizeof(WCHAR)))
1506 ml->ret = macho_search_and_load_file(ml->pcs, name, addr, &ml->macho_info);
1507 return FALSE;
1509 return TRUE;
1512 /******************************************************************
1513 * macho_load_module
1515 * Loads a Mach-O module and stores it in process' module list.
1516 * Also, find module real name and load address from
1517 * the real loaded modules list in pcs address space.
1519 struct module* macho_load_module(struct process* pcs, const WCHAR* name, unsigned long addr)
1521 struct macho_load ml;
1523 TRACE("(%p/%p, %s, 0x%08lx)\n", pcs, pcs->handle, debugstr_w(name), addr);
1525 ml.macho_info.flags = MACHO_INFO_MODULE;
1526 ml.ret = FALSE;
1528 if (pcs->dbg_hdr_addr) /* we're debugging a live target */
1530 ml.pcs = pcs;
1531 /* do only the lookup from the filename, not the path (as we lookup module
1532 * name in the process' loaded module list)
1534 ml.name = strrchrW(name, '/');
1535 if (!ml.name++) ml.name = name;
1536 ml.ret = FALSE;
1538 if (!macho_enum_modules_internal(pcs, NULL, macho_load_cb, &ml))
1539 return NULL;
1541 else if (addr)
1543 ml.name = name;
1544 ml.ret = macho_search_and_load_file(pcs, ml.name, addr, &ml.macho_info);
1546 if (!ml.ret) return NULL;
1547 assert(ml.macho_info.module);
1548 return ml.macho_info.module;
1551 #else /* HAVE_MACH_O_LOADER_H */
1553 BOOL macho_find_section(struct image_file_map* ifm, const char* segname, const char* sectname, struct image_section_map* ism)
1555 return FALSE;
1558 const char* macho_map_section(struct image_section_map* ism)
1560 return NULL;
1563 void macho_unmap_section(struct image_section_map* ism)
1567 DWORD_PTR macho_get_map_rva(const struct image_section_map* ism)
1569 return 0;
1572 unsigned macho_get_map_size(const struct image_section_map* ism)
1574 return 0;
1577 BOOL macho_synchronize_module_list(struct process* pcs)
1579 return FALSE;
1582 BOOL macho_fetch_file_info(const WCHAR* name, DWORD_PTR* base,
1583 DWORD* size, DWORD* checksum)
1585 return FALSE;
1588 BOOL macho_read_wine_loader_dbg_info(struct process* pcs)
1590 return FALSE;
1593 BOOL macho_enum_modules(HANDLE hProc, enum_modules_cb cb, void* user)
1595 return FALSE;
1598 struct module* macho_load_module(struct process* pcs, const WCHAR* name, unsigned long addr)
1600 return NULL;
1603 BOOL macho_load_debug_info(struct module* module)
1605 return FALSE;
1607 #endif /* HAVE_MACH_O_LOADER_H */