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
25 #include "wine/port.h"
30 #ifdef HAVE_SYS_STAT_H
31 # include <sys/stat.h>
33 #ifdef HAVE_SYS_MMAN_H
34 # include <sys/mman.h>
38 #define WIN32_NO_STATUS
39 #include "dbghelp_private.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>
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
{
62 uint32_t infoArrayCount
;
63 const struct dyld_image_info
*infoArray
;
65 int processDetachedFromSharedRegion
;
69 #ifdef WORDS_BIGENDIAN
70 #define swap_ulong_be_to_host(n) (n)
72 #define swap_ulong_be_to_host(n) (RtlUlongByteSwap(n))
75 WINE_DEFAULT_DEBUG_CHANNEL(dbghelp_macho
);
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
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
95 struct macho_module_info
97 struct image_file_map file_map
;
98 unsigned long load_addr
;
99 unsigned short in_use
: 1,
103 #define MACHO_INFO_DEBUG_HEADER 0x0001
104 #define MACHO_INFO_MODULE 0x0002
105 #define MACHO_INFO_NAME 0x0004
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 /******************************************************************
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
;
138 *out_aligned_len
= *out_aligned_end
- *out_aligned_offset
;
140 *out_misalign
= misalign
;
143 /******************************************************************
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
,
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
;
166 return (const char*)aligned_ptr
+ misalign
;
169 /******************************************************************
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
;
184 macho_calc_range(fmap
, offset
, len
, &aligned_offset
, &aligned_map_end
,
185 &map_size
, &misalign
);
188 aligned_ptr
= (char*)*mapped
- misalign
;
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
);
195 *mapped
= IMAGE_NO_MAP
;
197 *base
= IMAGE_NO_MAP
;
201 /******************************************************************
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
);
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
;
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 /******************************************************************
256 * Unmaps two ranges (offset, length in bytes) of a Mach-O file
257 * from memory. Use for ranges which were mapped by
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
);
281 if (offset1
< offset2
)
283 macho_unmap_range(NULL
, mapped1
, fmap
, offset1
, offset2
+ len2
- offset1
);
284 *mapped2
= IMAGE_NO_MAP
;
288 macho_unmap_range(NULL
, mapped2
, fmap
, offset2
, offset1
+ len1
- offset2
);
289 *mapped1
= IMAGE_NO_MAP
;
294 /******************************************************************
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
;
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);
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))
329 /******************************************************************
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
)
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 /******************************************************************
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
)
365 return ism
->fmap
->u
.macho
.sect
[ism
->sidx
].section
->addr
- ism
->fmap
->u
.macho
.segs_start
;
368 /******************************************************************
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
)
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
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*),
435 const struct load_command
* lc
;
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
))
449 if (cmd
&& cmd
!= lc
->cmd
) continue;
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
;
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
;
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
;
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");
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
= §ion
[i
];
518 fmap
->sect
[*section_index
].mapped
= IMAGE_NO_MAP
;
525 /******************************************************************
528 static inline void reset_file_map(struct image_file_map
* ifm
)
530 struct macho_file_map
* fmap
= &ifm
->u
.macho
;
533 fmap
->load_commands
= IMAGE_NO_MAP
;
534 fmap
->num_sections
= 0;
538 /******************************************************************
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
;
553 TRACE("(%s, %p)\n", debugstr_w(filenameW
), fmap
);
557 ifm
->modtype
= DMT_MACHO
;
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");
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
));
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
);
586 if (read(fmap
->fd
, &fat_header
, sizeof(fat_header
)) != sizeof(fat_header
))
588 TRACE("failed to read fat header: %d\n", errno
);
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
))
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
);
608 if (i
>= narch
) goto done
;
609 TRACE("... found target arch (%d)\n", TARGET_CPU_TYPE
);
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
))
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
)
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)
641 TRACE("%d sections\n", fmap
->num_sections
);
643 fmap
->sect
= HeapAlloc(GetProcessHeap(), 0, fmap
->num_sections
* sizeof(fmap
->sect
[0]));
648 fmap
->segs_start
= ~0L;
651 if (macho_enum_load_commands(fmap
, TARGET_SEGMENT_COMMAND
, macho_load_section_info
, &i
) < 0)
653 fmap
->num_sections
= 0;
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
);
664 macho_unmap_file(ifm
);
665 HeapFree(GetProcessHeap(), 0, filename
);
669 /******************************************************************
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
;
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 /******************************************************************
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
)
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
);
718 struct hash_table_elt ht_elt
;
719 struct symt_compiland
* compiland
;
721 unsigned char is_code
:1,
727 struct macho_debug_info
729 struct macho_file_map
* fmap
;
730 struct module
* module
;
732 struct hash_table ht_symtab
;
735 /******************************************************************
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
;
762 hash_table_add(&mdi
->ht_symtab
, &ste
->ht_elt
);
765 /******************************************************************
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
;
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
))
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
))
793 macho_unmap_ranges(fmap
, sc
->symoff
, sc
->nsyms
* sizeof(macho_nlist
),
794 sc
->stroff
, sc
->strsize
, (const void**)&stab
, (const void**)&stabstr
);
799 /******************************************************************
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
;
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
))
832 switch (sym
->symt
.tag
)
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
;
844 if (func
->address
== ste
->addr
)
848 data
= (struct symt_data
*)sym
;
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
;
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
;
881 TRACE("Ignoring tag %u\n", sym
->symt
.tag
);
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
)))
906 if (ste
->used
) continue;
908 sym
= symt_find_nearest(module
, ste
->addr
);
910 symt_get_address(&sym
->symt
, &addr
);
911 if (sym
&& ste
->addr
== addr
)
918 /* If neither symbol has a correct size (ours never does), we
919 * consider them both to be markers. No warning is needed in
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
,
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
)
945 symt_new_function(module
, ste
->compiland
, ste
->ht_elt
.name
,
952 loc
.kind
= loc_absolute
;
954 loc
.offset
= ste
->addr
;
955 symt_new_global_variable(module
, ste
->compiland
, ste
->ht_elt
.name
,
956 !ste
->is_global
, loc
, 0, NULL
);
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
)
977 struct macho_debug_info mdi
;
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
));
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
;
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
);
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
))
1009 pool_destroy(&mdi
.pool
);
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
);
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 /******************************************************************
1045 * Loads the information for Mach-O module stored in 'filename'.
1046 * The module has been loaded at 'load_addr' address.
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)
1052 static BOOL
macho_load_file(struct process
* pcs
, const WCHAR
* filename
,
1053 unsigned long load_addr
, struct macho_info
* macho_info
)
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
;
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
;
1090 #ifndef __LP64__ /* No reading the symtab with nlist(3) in LP64 */
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
)
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
;
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
;
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
);
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
))
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
)
1158 ptr
= HeapAlloc(GetProcessHeap(), 0, (lstrlenW(filename
) + 1) * sizeof(WCHAR
));
1161 strcpyW(ptr
, filename
);
1162 macho_info
->module_name
= ptr
;
1165 TRACE("module_name = %p %s\n", macho_info
->module_name
, debugstr_w(macho_info
->module_name
));
1168 macho_unmap_file(&fmap
);
1170 TRACE(" => %d\n", 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
,
1182 struct macho_info
* macho_info
)
1186 WCHAR
* pathW
= NULL
;
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
, ':');
1203 fn
= HeapAlloc(GetProcessHeap(), 0, (lstrlenW(filename
) + 1 + lstrlenW(s
) + 1) * sizeof(WCHAR
));
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
);
1211 s
= (t
) ? (t
+1) : NULL
;
1214 TRACE(" => %d\n", ret
);
1215 HeapFree(GetProcessHeap(), 0, pathW
);
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
)
1230 unsigned int index
= 0;
1233 TRACE("(%p/%p, %s, 0x%08lx, %p)\n", pcs
, pcs
->handle
, debugstr_w(filename
), load_addr
,
1236 while (!ret
&& (path
= wine_dll_enum_load_path( index
++ )))
1241 len
= MultiByteToWideChar(CP_UNIXCP
, 0, path
, -1, NULL
, 0);
1243 name
= HeapAlloc( GetProcessHeap(), 0,
1244 (len
+ lstrlenW(filename
) + 2) * sizeof(WCHAR
) );
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
);
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
)
1267 struct module
* module
;
1268 static const WCHAR S_libstdcPPW
[] = {'l','i','b','s','t','d','c','+','+','\0'};
1271 TRACE("(%p/%p, %s, 0x%08lx, %p)\n", pcs
, pcs
->handle
, debugstr_w(filename
), load_addr
,
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). */
1293 if ((p
= strrchrW(filename
, '/'))) p
++;
1295 ret
= macho_load_file_from_path(pcs
, p
, load_addr
,
1296 getenv("DYLD_LIBRARY_PATH"), macho_info
);
1298 /* Try the path as given. */
1300 ret
= macho_load_file(pcs
, filename
, load_addr
, macho_info
);
1301 /* Try DYLD_FALLBACK_LIBRARY_PATH, with just the filename (no directories). */
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
);
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
;
1327 WCHAR bufstrW
[MAX_PATH
];
1330 TRACE("(%p/%p, %s, %p, %p)\n", pcs
, pcs
->handle
, debugstr_w(main_name
), cb
,
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
)
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
);
1343 !ReadProcessMemory(pcs
->handle
, image_infos
.infoArray
,
1344 info_array
, len
, NULL
))
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;
1363 HeapFree(GetProcessHeap(), 0, info_array
);
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
);
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;
1404 ms
.macho_info
.flags
= MACHO_INFO_MODULE
;
1405 if (!macho_enum_modules_internal(pcs
, NULL
, macho_enum_sync_cb
, &ms
))
1408 module
= pcs
->lmodules
;
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
;
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
)
1464 struct macho_info macho_info
;
1467 TRACE("(%p, %p, %p)\n", hProc
, cb
, user
);
1468 memset(&pcs
, 0, sizeof(pcs
));
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
);
1480 struct process
* pcs
;
1481 struct macho_info macho_info
;
1486 /******************************************************************
1489 * Callback for macho_load_module, used to walk the list of loaded
1492 static BOOL
macho_load_cb(const WCHAR
* name
, unsigned long addr
, void* user
)
1494 struct macho_load
* ml
= user
;
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
, '/');
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
);
1512 /******************************************************************
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
;
1528 if (pcs
->dbg_hdr_addr
) /* we're debugging a live target */
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
;
1538 if (!macho_enum_modules_internal(pcs
, NULL
, macho_load_cb
, &ml
))
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
)
1558 const char* macho_map_section(struct image_section_map
* ism
)
1563 void macho_unmap_section(struct image_section_map
* ism
)
1567 DWORD_PTR
macho_get_map_rva(const struct image_section_map
* ism
)
1572 unsigned macho_get_map_size(const struct image_section_map
* ism
)
1577 BOOL
macho_synchronize_module_list(struct process
* pcs
)
1582 BOOL
macho_fetch_file_info(const WCHAR
* name
, DWORD_PTR
* base
,
1583 DWORD
* size
, DWORD
* checksum
)
1588 BOOL
macho_read_wine_loader_dbg_info(struct process
* pcs
)
1593 BOOL
macho_enum_modules(HANDLE hProc
, enum_modules_cb cb
, void* user
)
1598 struct module
* macho_load_module(struct process
* pcs
, const WCHAR
* name
, unsigned long addr
)
1603 BOOL
macho_load_debug_info(struct module
* module
)
1607 #endif /* HAVE_MACH_O_LOADER_H */