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"
27 #ifdef HAVE_MACH_O_LOADER_H
28 #include <CoreFoundation/CFString.h>
29 #define LoadResource mac_LoadResource
30 #define GetCurrentThread mac_GetCurrentThread
31 #include <CoreServices/CoreServices.h>
33 #undef GetCurrentThread
40 #ifdef HAVE_SYS_STAT_H
41 # include <sys/stat.h>
43 #ifdef HAVE_SYS_MMAN_H
44 # include <sys/mman.h>
48 #define WIN32_NO_STATUS
49 #include "dbghelp_private.h"
51 #include "wine/library.h"
52 #include "wine/debug.h"
53 #include "wine/heap.h"
54 #include "image_private.h"
56 #ifdef HAVE_MACH_O_LOADER_H
58 #include <mach-o/fat.h>
59 #include <mach-o/loader.h>
60 #include <mach-o/nlist.h>
61 #include <mach-o/dyld.h>
63 struct dyld_image_info32
{
64 uint32_t /* const struct mach_header* */ imageLoadAddress
;
65 uint32_t /* const char* */ imageFilePath
;
66 uint32_t /* uintptr_t */ imageFileModDate
;
69 struct dyld_all_image_infos32
{
71 uint32_t infoArrayCount
;
72 uint32_t /* const struct dyld_image_info* */ infoArray
;
75 struct dyld_image_info64
{
76 uint64_t /* const struct mach_header* */ imageLoadAddress
;
77 uint64_t /* const char* */ imageFilePath
;
78 uint64_t /* uintptr_t */ imageFileModDate
;
81 struct dyld_all_image_infos64
{
83 uint32_t infoArrayCount
;
84 uint64_t /* const struct dyld_image_info* */ infoArray
;
87 union wine_image_info
{
88 struct dyld_image_info32 info32
;
89 struct dyld_image_info64 info64
;
92 union wine_all_image_infos
{
93 struct dyld_all_image_infos32 infos32
;
94 struct dyld_all_image_infos64 infos64
;
97 #ifdef WORDS_BIGENDIAN
98 #define swap_ulong_be_to_host(n) (n)
100 #define swap_ulong_be_to_host(n) (RtlUlongByteSwap(n))
103 WINE_DEFAULT_DEBUG_CHANNEL(dbghelp_macho
);
106 /* Bitmask for Mach-O image header flags indicating that the image is in dyld's
107 shared cached. That implies that its segments are mapped non-contiguously.
108 This value isn't defined anywhere in headers. It's used in dyld and in
109 debuggers which support OS X as a magic number.
111 The flag also isn't set in the on-disk image file. It's only set in
113 #define MACHO_DYLD_IN_SHARED_CACHE 0x80000000
116 #define UUID_STRING_LEN 37 /* 16 bytes at 2 hex digits apiece, 4 dashes, and the null terminator */
119 struct macho_module_info
121 struct image_file_map file_map
;
122 unsigned long load_addr
;
123 unsigned short in_use
: 1,
130 unsigned int section_index
;
133 #define MACHO_INFO_DEBUG_HEADER 0x0001
134 #define MACHO_INFO_MODULE 0x0002
135 #define MACHO_INFO_NAME 0x0004
139 unsigned flags
; /* IN one (or several) of the MACHO_INFO constants */
140 unsigned long dbg_hdr_addr
; /* OUT address of debug header (if MACHO_INFO_DEBUG_HEADER is set) */
141 struct module
* module
; /* OUT loaded module (if MACHO_INFO_MODULE is set) */
142 const WCHAR
* module_name
; /* OUT found module name (if MACHO_INFO_NAME is set) */
145 static void macho_unmap_file(struct image_file_map
* fmap
);
147 static char* format_uuid(const uint8_t uuid
[16], char out
[UUID_STRING_LEN
])
149 sprintf(out
, "%02X%02X%02X%02X-%02X%02X-%02X%02X-%02X%02X-%02X%02X%02X%02X%02X%02X",
150 uuid
[0], uuid
[1], uuid
[2], uuid
[3], uuid
[4], uuid
[5], uuid
[6], uuid
[7],
151 uuid
[8], uuid
[9], uuid
[10], uuid
[11], uuid
[12], uuid
[13], uuid
[14], uuid
[15]);
155 /******************************************************************
158 * For a range (offset & length) of a single architecture within
159 * a Mach-O file, calculate the page-aligned range of the whole file
160 * that encompasses it. For a fat binary, the architecture will
161 * itself be offset within the file, so take that into account.
163 static void macho_calc_range(const struct macho_file_map
* fmap
, unsigned long offset
,
164 unsigned long len
, unsigned long* out_aligned_offset
,
165 unsigned long* out_aligned_end
, unsigned long* out_aligned_len
,
166 unsigned long* out_misalign
)
168 unsigned long pagemask
= sysconf( _SC_PAGESIZE
) - 1;
169 unsigned long file_offset
, misalign
;
171 file_offset
= fmap
->arch_offset
+ offset
;
172 misalign
= file_offset
& pagemask
;
173 *out_aligned_offset
= file_offset
- misalign
;
174 *out_aligned_end
= (file_offset
+ len
+ pagemask
) & ~pagemask
;
176 *out_aligned_len
= *out_aligned_end
- *out_aligned_offset
;
178 *out_misalign
= misalign
;
181 /******************************************************************
184 * Maps a range (offset, length in bytes) from a Mach-O file into memory
186 static const char* macho_map_range(const struct macho_file_map
* fmap
, unsigned long offset
, unsigned long len
,
189 unsigned long misalign
, aligned_offset
, aligned_map_end
, map_size
;
190 const void* aligned_ptr
;
192 TRACE("(%p/%d, 0x%08lx, 0x%08lx)\n", fmap
, fmap
->fd
, offset
, len
);
194 macho_calc_range(fmap
, offset
, len
, &aligned_offset
, &aligned_map_end
,
195 &map_size
, &misalign
);
197 aligned_ptr
= mmap(NULL
, map_size
, PROT_READ
, MAP_PRIVATE
, fmap
->fd
, aligned_offset
);
199 TRACE("Mapped (0x%08lx - 0x%08lx) to %p\n", aligned_offset
, aligned_map_end
, aligned_ptr
);
201 if (aligned_ptr
== MAP_FAILED
) return IMAGE_NO_MAP
;
204 return (const char*)aligned_ptr
+ misalign
;
207 /******************************************************************
210 * Unmaps a range (offset, length in bytes) of a Mach-O file from memory
212 static void macho_unmap_range(const char** base
, const void** mapped
, const struct macho_file_map
* fmap
,
213 unsigned long offset
, unsigned long len
)
215 TRACE("(%p, %p, %p/%d, 0x%08lx, 0x%08lx)\n", base
, mapped
, fmap
, fmap
->fd
, offset
, len
);
217 if ((mapped
&& *mapped
!= IMAGE_NO_MAP
) || (base
&& *base
!= IMAGE_NO_MAP
))
219 unsigned long misalign
, aligned_offset
, aligned_map_end
, map_size
;
222 macho_calc_range(fmap
, offset
, len
, &aligned_offset
, &aligned_map_end
,
223 &map_size
, &misalign
);
226 aligned_ptr
= (char*)*mapped
- misalign
;
228 aligned_ptr
= (void*)*base
;
229 if (munmap(aligned_ptr
, map_size
) < 0)
230 WARN("Couldn't unmap the range\n");
231 TRACE("Unmapped (0x%08lx - 0x%08lx) from %p - %p\n", aligned_offset
, aligned_map_end
, aligned_ptr
, (char*)aligned_ptr
+ map_size
);
233 *mapped
= IMAGE_NO_MAP
;
235 *base
= IMAGE_NO_MAP
;
239 /******************************************************************
242 * Maps two ranges (offset, length in bytes) from a Mach-O file
243 * into memory. If the two ranges overlap, use one mmap so that
244 * the munmap doesn't fragment the mapping.
246 static BOOL
macho_map_ranges(const struct macho_file_map
* fmap
,
247 unsigned long offset1
, unsigned long len1
,
248 unsigned long offset2
, unsigned long len2
,
249 const void** mapped1
, const void** mapped2
)
251 unsigned long aligned_offset1
, aligned_map_end1
;
252 unsigned long aligned_offset2
, aligned_map_end2
;
254 TRACE("(%p/%d, 0x%08lx, 0x%08lx, 0x%08lx, 0x%08lx, %p, %p)\n", fmap
, fmap
->fd
,
255 offset1
, len1
, offset2
, len2
, mapped1
, mapped2
);
257 macho_calc_range(fmap
, offset1
, len1
, &aligned_offset1
, &aligned_map_end1
, NULL
, NULL
);
258 macho_calc_range(fmap
, offset2
, len2
, &aligned_offset2
, &aligned_map_end2
, NULL
, NULL
);
260 if (aligned_map_end1
< aligned_offset2
|| aligned_map_end2
< aligned_offset1
)
262 *mapped1
= macho_map_range(fmap
, offset1
, len1
, NULL
);
263 if (*mapped1
!= IMAGE_NO_MAP
)
265 *mapped2
= macho_map_range(fmap
, offset2
, len2
, NULL
);
266 if (*mapped2
== IMAGE_NO_MAP
)
267 macho_unmap_range(NULL
, mapped1
, fmap
, offset1
, len1
);
272 if (offset1
< offset2
)
274 *mapped1
= macho_map_range(fmap
, offset1
, offset2
+ len2
- offset1
, NULL
);
275 if (*mapped1
!= IMAGE_NO_MAP
)
276 *mapped2
= (const char*)*mapped1
+ offset2
- offset1
;
280 *mapped2
= macho_map_range(fmap
, offset2
, offset1
+ len1
- offset2
, NULL
);
281 if (*mapped2
!= IMAGE_NO_MAP
)
282 *mapped1
= (const char*)*mapped2
+ offset1
- offset2
;
286 TRACE(" => %p, %p\n", *mapped1
, *mapped2
);
288 return (*mapped1
!= IMAGE_NO_MAP
) && (*mapped2
!= IMAGE_NO_MAP
);
291 /******************************************************************
294 * Unmaps two ranges (offset, length in bytes) of a Mach-O file
295 * from memory. Use for ranges which were mapped by
298 static void macho_unmap_ranges(const struct macho_file_map
* fmap
,
299 unsigned long offset1
, unsigned long len1
,
300 unsigned long offset2
, unsigned long len2
,
301 const void** mapped1
, const void** mapped2
)
303 unsigned long aligned_offset1
, aligned_map_end1
;
304 unsigned long aligned_offset2
, aligned_map_end2
;
306 TRACE("(%p/%d, 0x%08lx, 0x%08lx, 0x%08lx, 0x%08lx, %p/%p, %p/%p)\n", fmap
, fmap
->fd
,
307 offset1
, len1
, offset2
, len2
, mapped1
, *mapped1
, mapped2
, *mapped2
);
309 macho_calc_range(fmap
, offset1
, len1
, &aligned_offset1
, &aligned_map_end1
, NULL
, NULL
);
310 macho_calc_range(fmap
, offset2
, len2
, &aligned_offset2
, &aligned_map_end2
, NULL
, NULL
);
312 if (aligned_map_end1
< aligned_offset2
|| aligned_map_end2
< aligned_offset1
)
314 macho_unmap_range(NULL
, mapped1
, fmap
, offset1
, len1
);
315 macho_unmap_range(NULL
, mapped2
, fmap
, offset2
, len2
);
319 if (offset1
< offset2
)
321 macho_unmap_range(NULL
, mapped1
, fmap
, offset1
, offset2
+ len2
- offset1
);
322 *mapped2
= IMAGE_NO_MAP
;
326 macho_unmap_range(NULL
, mapped2
, fmap
, offset2
, offset1
+ len1
- offset2
);
327 *mapped1
= IMAGE_NO_MAP
;
332 /******************************************************************
335 BOOL
macho_find_section(struct image_file_map
* ifm
, const char* segname
, const char* sectname
, struct image_section_map
* ism
)
337 struct macho_file_map
* fmap
;
339 char tmp
[sizeof(fmap
->sect
[0].section
.sectname
)];
341 /* Other parts of dbghelp use section names like ".eh_frame". Mach-O uses
342 names like "__eh_frame". Convert those. */
343 if (sectname
[0] == '.')
345 lstrcpynA(tmp
, "__", sizeof(tmp
));
346 lstrcpynA(tmp
+ 2, sectname
+ 1, sizeof(tmp
) - 2);
352 fmap
= &ifm
->u
.macho
;
353 for (i
= 0; i
< fmap
->num_sections
; i
++)
355 if (!fmap
->sect
[i
].ignored
&&
356 strcmp(fmap
->sect
[i
].section
.sectname
, sectname
) == 0 &&
357 (!segname
|| strcmp(fmap
->sect
[i
].section
.segname
, segname
) == 0))
372 /******************************************************************
375 const char* macho_map_section(struct image_section_map
* ism
)
377 struct macho_file_map
* fmap
= &ism
->fmap
->u
.macho
;
379 assert(ism
->fmap
->modtype
== DMT_MACHO
);
380 if (ism
->sidx
< 0 || ism
->sidx
>= ism
->fmap
->u
.macho
.num_sections
|| fmap
->sect
[ism
->sidx
].ignored
)
383 return macho_map_range(fmap
, fmap
->sect
[ism
->sidx
].section
.offset
, fmap
->sect
[ism
->sidx
].section
.size
,
384 &fmap
->sect
[ism
->sidx
].mapped
);
387 /******************************************************************
388 * macho_unmap_section
390 void macho_unmap_section(struct image_section_map
* ism
)
392 struct macho_file_map
* fmap
= &ism
->fmap
->u
.macho
;
394 if (ism
->sidx
>= 0 && ism
->sidx
< fmap
->num_sections
&& fmap
->sect
[ism
->sidx
].mapped
!= IMAGE_NO_MAP
)
396 macho_unmap_range(&fmap
->sect
[ism
->sidx
].mapped
, NULL
, fmap
, fmap
->sect
[ism
->sidx
].section
.offset
,
397 fmap
->sect
[ism
->sidx
].section
.size
);
401 /******************************************************************
404 DWORD_PTR
macho_get_map_rva(const struct image_section_map
* ism
)
406 if (ism
->sidx
< 0 || ism
->sidx
>= ism
->fmap
->u
.macho
.num_sections
||
407 ism
->fmap
->u
.macho
.sect
[ism
->sidx
].ignored
)
409 return ism
->fmap
->u
.macho
.sect
[ism
->sidx
].section
.addr
- ism
->fmap
->u
.macho
.segs_start
;
412 /******************************************************************
415 unsigned macho_get_map_size(const struct image_section_map
* ism
)
417 if (ism
->sidx
< 0 || ism
->sidx
>= ism
->fmap
->u
.macho
.num_sections
||
418 ism
->fmap
->u
.macho
.sect
[ism
->sidx
].ignored
)
420 return ism
->fmap
->u
.macho
.sect
[ism
->sidx
].section
.size
;
423 /******************************************************************
424 * macho_map_load_commands
426 * Maps the load commands from a Mach-O file into memory
428 static const struct load_command
* macho_map_load_commands(struct macho_file_map
* fmap
)
430 if (fmap
->load_commands
== IMAGE_NO_MAP
)
432 fmap
->load_commands
= (const struct load_command
*) macho_map_range(
433 fmap
, fmap
->header_size
, fmap
->mach_header
.sizeofcmds
, NULL
);
434 TRACE("Mapped load commands: %p\n", fmap
->load_commands
);
437 return fmap
->load_commands
;
440 /******************************************************************
441 * macho_unmap_load_commands
443 * Unmaps the load commands of a Mach-O file from memory
445 static void macho_unmap_load_commands(struct macho_file_map
* fmap
)
447 if (fmap
->load_commands
!= IMAGE_NO_MAP
)
449 TRACE("Unmapping load commands: %p\n", fmap
->load_commands
);
450 macho_unmap_range(NULL
, (const void**)&fmap
->load_commands
, fmap
,
451 fmap
->header_size
, fmap
->mach_header
.sizeofcmds
);
455 /******************************************************************
456 * macho_next_load_command
458 * Advance to the next load command
460 static const struct load_command
* macho_next_load_command(const struct load_command
* lc
)
462 return (const struct load_command
*)((const char*)lc
+ lc
->cmdsize
);
465 /******************************************************************
466 * macho_enum_load_commands
468 * Enumerates the load commands for a Mach-O file, selecting by
469 * the command type, calling a callback for each. If the callback
470 * returns <0, that indicates an error. If it returns >0, that means
471 * it's not interested in getting any more load commands.
472 * If this function returns <0, that's an error produced by the
473 * callback. If >=0, that's the count of load commands successfully
476 static int macho_enum_load_commands(struct image_file_map
*ifm
, unsigned cmd
,
477 int (*cb
)(struct image_file_map
*, const struct load_command
*, void*),
480 struct macho_file_map
* fmap
= &ifm
->u
.macho
;
481 const struct load_command
* lc
;
485 TRACE("(%p/%d, %u, %p, %p)\n", fmap
, fmap
->fd
, cmd
, cb
, user
);
487 if ((lc
= macho_map_load_commands(fmap
)) == IMAGE_NO_MAP
) return -1;
489 TRACE("%d total commands\n", fmap
->mach_header
.ncmds
);
491 for (i
= 0; i
< fmap
->mach_header
.ncmds
; i
++, lc
= macho_next_load_command(lc
))
495 if (cmd
&& cmd
!= lc
->cmd
) continue;
498 result
= cb(ifm
, lc
, user
);
499 TRACE("load_command[%d] (%p), cmd %u; callback => %d\n", i
, lc
, lc
->cmd
, result
);
500 if (result
) return (result
< 0) ? result
: count
;
506 /******************************************************************
507 * macho_count_sections
509 * Callback for macho_enum_load_commands. Counts the number of
510 * significant sections in a Mach-O file. All commands are
511 * expected to be of LC_SEGMENT[_64] type.
513 static int macho_count_sections(struct image_file_map
* ifm
, const struct load_command
* lc
, void* user
)
518 if (ifm
->addr_size
== 32)
520 const struct segment_command
*sc
= (const struct segment_command
*)lc
;
521 memcpy(segname
, sc
->segname
, sizeof(segname
));
526 const struct segment_command_64
*sc
= (const struct segment_command_64
*)lc
;
527 memcpy(segname
, sc
->segname
, sizeof(segname
));
531 TRACE("(%p/%d, %p, %p) segment %s\n", ifm
, ifm
->u
.macho
.fd
, lc
, user
,
532 debugstr_an(segname
, sizeof(segname
)));
534 ifm
->u
.macho
.num_sections
+= nsects
;
538 /******************************************************************
539 * macho_load_section_info
541 * Callback for macho_enum_load_commands. Accumulates the address
542 * range covered by the segments of a Mach-O file and builds the
543 * section map. All commands are expected to be of LC_SEGMENT[_64] type.
545 static int macho_load_section_info(struct image_file_map
* ifm
, const struct load_command
* lc
, void* user
)
547 struct macho_file_map
* fmap
= &ifm
->u
.macho
;
548 struct section_info
* info
= user
;
551 unsigned long tmp
, page_mask
= sysconf( _SC_PAGESIZE
) - 1;
552 uint64_t vmaddr
, vmsize
;
555 const void *sections
;
557 if (ifm
->addr_size
== 32)
559 const struct segment_command
*sc
= (const struct segment_command
*)lc
;
562 memcpy(segname
, sc
->segname
, sizeof(segname
));
564 sections
= (const void *)(sc
+ 1);
568 const struct segment_command_64
*sc
= (const struct segment_command_64
*)lc
;
571 memcpy(segname
, sc
->segname
, sizeof(segname
));
573 sections
= (const void *)(sc
+ 1);
576 TRACE("(%p/%d, %p, %p) before: 0x%08lx - 0x%08lx\n", fmap
, fmap
->fd
, lc
, user
,
577 (unsigned long)fmap
->segs_start
, (unsigned long)fmap
->segs_size
);
578 TRACE("Segment command vm: 0x%08lx - 0x%08lx\n", (unsigned long)vmaddr
,
579 (unsigned long)(vmaddr
+ vmsize
));
581 /* Images in the dyld shared cache have their segments mapped non-contiguously.
582 We don't know how to properly locate any of the segments other than __TEXT,
584 ignore
= (info
->split_segs
&& strcmp(segname
, SEG_TEXT
));
586 if (!strncmp(segname
, "WINE_", 5))
587 TRACE("Ignoring special Wine segment %s\n", debugstr_an(segname
, sizeof(segname
)));
588 else if (!strncmp(segname
, "__PAGEZERO", 10))
589 TRACE("Ignoring __PAGEZERO segment\n");
591 TRACE("Ignoring %s segment because image has split segments\n", segname
);
594 /* If this segment starts before previously-known earliest, record new earliest. */
595 if (vmaddr
< fmap
->segs_start
)
596 fmap
->segs_start
= vmaddr
;
598 /* If this segment extends beyond previously-known furthest, record new furthest. */
599 tmp
= (vmaddr
+ vmsize
+ page_mask
) & ~page_mask
;
600 if (fmap
->segs_size
< tmp
) fmap
->segs_size
= tmp
;
602 TRACE("after: 0x%08lx - 0x%08lx\n", (unsigned long)fmap
->segs_start
, (unsigned long)fmap
->segs_size
);
605 for (i
= 0; i
< nsects
; i
++)
607 if (ifm
->addr_size
== 32)
609 const struct section
*section
= &((const struct section
*)sections
)[i
];
610 memcpy(fmap
->sect
[info
->section_index
].section
.sectname
, section
->sectname
, sizeof(section
->sectname
));
611 memcpy(fmap
->sect
[info
->section_index
].section
.segname
, section
->segname
, sizeof(section
->segname
));
612 fmap
->sect
[info
->section_index
].section
.addr
= section
->addr
;
613 fmap
->sect
[info
->section_index
].section
.size
= section
->size
;
614 fmap
->sect
[info
->section_index
].section
.offset
= section
->offset
;
615 fmap
->sect
[info
->section_index
].section
.align
= section
->align
;
616 fmap
->sect
[info
->section_index
].section
.reloff
= section
->reloff
;
617 fmap
->sect
[info
->section_index
].section
.nreloc
= section
->nreloc
;
618 fmap
->sect
[info
->section_index
].section
.flags
= section
->flags
;
621 fmap
->sect
[info
->section_index
].section
= ((const struct section_64
*)sections
)[i
];
623 fmap
->sect
[info
->section_index
].mapped
= IMAGE_NO_MAP
;
624 fmap
->sect
[info
->section_index
].ignored
= ignore
;
625 info
->section_index
++;
631 /******************************************************************
634 * Callback for macho_enum_load_commands. Records the UUID load
635 * command of a Mach-O file.
637 static int find_uuid(struct image_file_map
* ifm
, const struct load_command
* lc
, void* user
)
639 ifm
->u
.macho
.uuid
= (const struct uuid_command
*)lc
;
643 /******************************************************************
646 static inline void reset_file_map(struct image_file_map
* ifm
)
648 struct macho_file_map
* fmap
= &ifm
->u
.macho
;
652 fmap
->load_commands
= IMAGE_NO_MAP
;
654 fmap
->num_sections
= 0;
658 /******************************************************************
661 * Maps a Mach-O file into memory (and checks it's a real Mach-O file)
663 static BOOL
macho_map_file(struct process
*pcs
, const WCHAR
*filenameW
,
664 BOOL split_segs
, struct image_file_map
* ifm
)
666 struct macho_file_map
* fmap
= &ifm
->u
.macho
;
667 struct fat_header fat_header
;
672 struct section_info info
;
674 cpu_type_t target_cpu
= (pcs
->is_64bit
) ? CPU_TYPE_X86_64
: CPU_TYPE_X86
;
675 uint32_t target_magic
= (pcs
->is_64bit
) ? MH_MAGIC_64
: MH_MAGIC
;
676 uint32_t target_cmd
= (pcs
->is_64bit
) ? LC_SEGMENT_64
: LC_SEGMENT
;
678 TRACE("(%s, %p)\n", debugstr_w(filenameW
), fmap
);
682 ifm
->modtype
= DMT_MACHO
;
683 ifm
->addr_size
= (pcs
->is_64bit
) ? 64 : 32;
684 fmap
->header_size
= (pcs
->is_64bit
) ? sizeof(struct mach_header_64
) : sizeof(struct mach_header
);
686 len
= WideCharToMultiByte(CP_UNIXCP
, 0, filenameW
, -1, NULL
, 0, NULL
, NULL
);
687 if (!(filename
= HeapAlloc(GetProcessHeap(), 0, len
)))
689 WARN("failed to allocate filename buffer\n");
692 WideCharToMultiByte(CP_UNIXCP
, 0, filenameW
, -1, filename
, len
, NULL
, NULL
);
694 /* check that the file exists */
695 if (stat(filename
, &statbuf
) == -1 || S_ISDIR(statbuf
.st_mode
))
697 TRACE("stat() failed or %s is directory: %s\n", debugstr_a(filename
), strerror(errno
));
701 /* Now open the file, so that we can mmap() it. */
702 if ((fmap
->fd
= open(filename
, O_RDONLY
)) == -1)
704 TRACE("failed to open file %s: %d\n", debugstr_a(filename
), errno
);
708 if (read(fmap
->fd
, &fat_header
, sizeof(fat_header
)) != sizeof(fat_header
))
710 TRACE("failed to read fat header: %d\n", errno
);
713 TRACE("... got possible fat header\n");
715 /* Fat header is always in big-endian order. */
716 if (swap_ulong_be_to_host(fat_header
.magic
) == FAT_MAGIC
)
718 int narch
= swap_ulong_be_to_host(fat_header
.nfat_arch
);
719 for (i
= 0; i
< narch
; i
++)
721 struct fat_arch fat_arch
;
722 if (read(fmap
->fd
, &fat_arch
, sizeof(fat_arch
)) != sizeof(fat_arch
))
724 if (swap_ulong_be_to_host(fat_arch
.cputype
) == target_cpu
)
726 fmap
->arch_offset
= swap_ulong_be_to_host(fat_arch
.offset
);
730 if (i
>= narch
) goto done
;
731 TRACE("... found target arch (%d)\n", target_cpu
);
735 fmap
->arch_offset
= 0;
736 TRACE("... not a fat header\n");
739 /* Individual architecture (standalone or within a fat file) is in its native byte order. */
740 lseek(fmap
->fd
, fmap
->arch_offset
, SEEK_SET
);
741 if (read(fmap
->fd
, &fmap
->mach_header
, sizeof(fmap
->mach_header
)) != sizeof(fmap
->mach_header
))
743 TRACE("... got possible Mach header\n");
744 /* and check for a Mach-O header */
745 if (fmap
->mach_header
.magic
!= target_magic
||
746 fmap
->mach_header
.cputype
!= target_cpu
) goto done
;
747 /* Make sure the file type is one of the ones we expect. */
748 switch (fmap
->mach_header
.filetype
)
759 TRACE("... verified Mach header\n");
761 fmap
->num_sections
= 0;
762 if (macho_enum_load_commands(ifm
, target_cmd
, macho_count_sections
, NULL
) < 0)
764 TRACE("%d sections\n", fmap
->num_sections
);
766 fmap
->sect
= HeapAlloc(GetProcessHeap(), 0, fmap
->num_sections
* sizeof(fmap
->sect
[0]));
771 fmap
->segs_start
= ~0L;
773 info
.split_segs
= split_segs
;
774 info
.section_index
= 0;
775 if (macho_enum_load_commands(ifm
, target_cmd
, macho_load_section_info
, &info
) < 0)
777 fmap
->num_sections
= 0;
781 fmap
->segs_size
-= fmap
->segs_start
;
782 TRACE("segs_start: 0x%08lx, segs_size: 0x%08lx\n", (unsigned long)fmap
->segs_start
,
783 (unsigned long)fmap
->segs_size
);
785 if (macho_enum_load_commands(ifm
, LC_UUID
, find_uuid
, NULL
) < 0)
789 char uuid_string
[UUID_STRING_LEN
];
790 TRACE("UUID %s\n", format_uuid(fmap
->uuid
->uuid
, uuid_string
));
793 TRACE("no UUID found\n");
798 macho_unmap_file(ifm
);
799 HeapFree(GetProcessHeap(), 0, filename
);
803 /******************************************************************
806 * Unmaps a Mach-O file from memory (previously mapped with macho_map_file)
808 static void macho_unmap_file(struct image_file_map
* ifm
)
810 struct image_file_map
* cursor
;
812 TRACE("(%p/%d)\n", ifm
, ifm
->u
.macho
.fd
);
817 struct image_file_map
* next
;
819 if (ifm
->u
.macho
.fd
!= -1)
821 struct image_section_map ism
;
824 for (ism
.sidx
= 0; ism
.sidx
< ifm
->u
.macho
.num_sections
; ism
.sidx
++)
825 macho_unmap_section(&ism
);
827 HeapFree(GetProcessHeap(), 0, ifm
->u
.macho
.sect
);
828 macho_unmap_load_commands(&ifm
->u
.macho
);
829 close(ifm
->u
.macho
.fd
);
830 ifm
->u
.macho
.fd
= -1;
833 next
= cursor
->u
.macho
.dsym
;
835 HeapFree(GetProcessHeap(), 0, cursor
);
840 /******************************************************************
843 * Checks if a section, identified by sectidx which is a 1-based
844 * index into the sections of all segments, in order of load
845 * commands, contains code.
847 static BOOL
macho_sect_is_code(struct macho_file_map
* fmap
, unsigned char sectidx
)
851 TRACE("(%p/%d, %u)\n", fmap
, fmap
->fd
, sectidx
);
853 if (!sectidx
) return FALSE
;
855 sectidx
--; /* convert from 1-based to 0-based */
856 if (sectidx
>= fmap
->num_sections
|| fmap
->sect
[sectidx
].ignored
) return FALSE
;
858 ret
= (!(fmap
->sect
[sectidx
].section
.flags
& SECTION_TYPE
) &&
859 (fmap
->sect
[sectidx
].section
.flags
& (S_ATTR_PURE_INSTRUCTIONS
|S_ATTR_SOME_INSTRUCTIONS
)));
860 TRACE("-> %d\n", ret
);
866 struct hash_table_elt ht_elt
;
867 struct symt_compiland
* compiland
;
869 unsigned char is_code
:1,
875 struct macho_debug_info
877 struct macho_file_map
* fmap
;
878 struct module
* module
;
880 struct hash_table ht_symtab
;
883 /******************************************************************
886 * Callback for stabs_parse. Collect symbol definitions.
888 static void macho_stabs_def_cb(struct module
* module
, unsigned long load_offset
,
889 const char* name
, unsigned long offset
,
890 BOOL is_public
, BOOL is_global
, unsigned char sectidx
,
891 struct symt_compiland
* compiland
, void* user
)
893 struct macho_debug_info
* mdi
= user
;
894 struct symtab_elt
* ste
;
896 TRACE("(%p, 0x%08lx, %s, 0x%08lx, %d, %d, %u, %p, %p/%p/%d)\n", module
, load_offset
,
897 debugstr_a(name
), offset
, is_public
, is_global
, sectidx
,
898 compiland
, mdi
, mdi
->fmap
, mdi
->fmap
->fd
);
900 /* Defer the creation of new non-debugging symbols until after we've
901 * finished parsing the stabs. */
902 ste
= pool_alloc(&mdi
->pool
, sizeof(*ste
));
903 ste
->ht_elt
.name
= pool_strdup(&mdi
->pool
, name
);
904 ste
->compiland
= compiland
;
905 ste
->addr
= load_offset
+ offset
;
906 ste
->is_code
= !!macho_sect_is_code(mdi
->fmap
, sectidx
);
907 ste
->is_public
= !!is_public
;
908 ste
->is_global
= !!is_global
;
910 hash_table_add(&mdi
->ht_symtab
, &ste
->ht_elt
);
913 /******************************************************************
916 * Callback for macho_enum_load_commands. Processes the LC_SYMTAB
917 * load commands from the Mach-O file.
919 static int macho_parse_symtab(struct image_file_map
* ifm
,
920 const struct load_command
* lc
, void* user
)
922 struct macho_file_map
* fmap
= &ifm
->u
.macho
;
923 const struct symtab_command
* sc
= (const struct symtab_command
*)lc
;
924 struct macho_debug_info
* mdi
= user
;
927 size_t stabsize
= (ifm
->addr_size
== 32) ? sizeof(struct nlist
) : sizeof(struct nlist_64
);
930 TRACE("(%p/%d, %p, %p) %u syms at 0x%08x, strings 0x%08x - 0x%08x\n", fmap
, fmap
->fd
, lc
,
931 user
, sc
->nsyms
, sc
->symoff
, sc
->stroff
, sc
->stroff
+ sc
->strsize
);
933 if (!macho_map_ranges(fmap
, sc
->symoff
, sc
->nsyms
* stabsize
,
934 sc
->stroff
, sc
->strsize
, (const void**)&stab
, (const void**)&stabstr
))
937 if (!stabs_parse(mdi
->module
,
938 mdi
->module
->format_info
[DFI_MACHO
]->u
.macho_info
->load_addr
- fmap
->segs_start
,
939 stab
, sc
->nsyms
* stabsize
,
940 stabstr
, sc
->strsize
, macho_stabs_def_cb
, mdi
))
943 macho_unmap_ranges(fmap
, sc
->symoff
, sc
->nsyms
* stabsize
,
944 sc
->stroff
, sc
->strsize
, (const void**)&stab
, (const void**)&stabstr
);
949 /******************************************************************
952 * Integrate the non-debugging symbols we've gathered into the
953 * symbols that were generated during stabs parsing.
955 static void macho_finish_stabs(struct module
* module
, struct hash_table
* ht_symtab
)
957 struct hash_table_iter hti_ours
;
958 struct symtab_elt
* ste
;
959 BOOL adjusted
= FALSE
;
961 TRACE("(%p, %p)\n", module
, ht_symtab
);
963 /* For each of our non-debugging symbols, see if it can provide some
964 * missing details to one of the module's known symbols. */
965 hash_table_iter_init(ht_symtab
, &hti_ours
, NULL
);
966 while ((ste
= hash_table_iter_up(&hti_ours
)))
968 struct hash_table_iter hti_modules
;
971 struct symt_function
* func
;
972 struct symt_data
* data
;
974 hash_table_iter_init(&module
->ht_symbols
, &hti_modules
, ste
->ht_elt
.name
);
975 while ((ptr
= hash_table_iter_up(&hti_modules
)))
977 sym
= CONTAINING_RECORD(ptr
, struct symt_ht
, hash_elt
);
979 if (strcmp(sym
->hash_elt
.name
, ste
->ht_elt
.name
))
982 switch (sym
->symt
.tag
)
985 func
= (struct symt_function
*)sym
;
986 if (func
->address
== module
->format_info
[DFI_MACHO
]->u
.macho_info
->load_addr
)
988 TRACE("Adjusting function %p/%s!%s from 0x%08lx to 0x%08lx\n", func
,
989 debugstr_w(module
->module
.ModuleName
), sym
->hash_elt
.name
,
990 func
->address
, ste
->addr
);
991 func
->address
= ste
->addr
;
994 if (func
->address
== ste
->addr
)
998 data
= (struct symt_data
*)sym
;
1002 case DataIsFileStatic
:
1003 if (data
->u
.var
.offset
== module
->format_info
[DFI_MACHO
]->u
.macho_info
->load_addr
)
1005 TRACE("Adjusting data symbol %p/%s!%s from 0x%08lx to 0x%08lx\n",
1006 data
, debugstr_w(module
->module
.ModuleName
), sym
->hash_elt
.name
,
1007 data
->u
.var
.offset
, ste
->addr
);
1008 data
->u
.var
.offset
= ste
->addr
;
1011 if (data
->u
.var
.offset
== ste
->addr
)
1013 enum DataKind new_kind
;
1015 new_kind
= ste
->is_global
? DataIsGlobal
: DataIsFileStatic
;
1016 if (data
->kind
!= new_kind
)
1018 WARN("Changing kind for %p/%s!%s from %d to %d\n", sym
,
1019 debugstr_w(module
->module
.ModuleName
), sym
->hash_elt
.name
,
1020 (int)data
->kind
, (int)new_kind
);
1021 data
->kind
= new_kind
;
1031 TRACE("Ignoring tag %u\n", sym
->symt
.tag
);
1039 /* since we may have changed some addresses, mark the module to be resorted */
1040 module
->sortlist_valid
= FALSE
;
1043 /* Mark any of our non-debugging symbols which fall on an already-used
1044 * address as "used". This allows us to skip them in the next loop,
1045 * below. We do this in separate loops because symt_new_* marks the
1046 * list as needing sorting and symt_find_nearest sorts if needed,
1047 * causing thrashing. */
1048 if (!(dbghelp_options
& SYMOPT_PUBLICS_ONLY
))
1050 hash_table_iter_init(ht_symtab
, &hti_ours
, NULL
);
1051 while ((ste
= hash_table_iter_up(&hti_ours
)))
1053 struct symt_ht
* sym
;
1056 if (ste
->used
) continue;
1058 sym
= symt_find_nearest(module
, ste
->addr
);
1060 symt_get_address(&sym
->symt
, &addr
);
1061 if (sym
&& ste
->addr
== addr
)
1068 /* If neither symbol has a correct size (ours never does), we
1069 * consider them both to be markers. No warning is needed in
1071 * Also, we check that we don't have two symbols, one local, the other
1072 * global, which is legal.
1074 symt_get_info(module
, &sym
->symt
, TI_GET_LENGTH
, &size
);
1075 symt_get_info(module
, &sym
->symt
, TI_GET_DATAKIND
, &kind
);
1076 if (size
&& kind
== (ste
->is_global
? DataIsGlobal
: DataIsFileStatic
))
1077 FIXME("Duplicate in %s: %s<%08lx> %s<%s-%s>\n",
1078 debugstr_w(module
->module
.ModuleName
),
1079 ste
->ht_elt
.name
, ste
->addr
,
1081 wine_dbgstr_longlong(addr
), wine_dbgstr_longlong(size
));
1086 /* For any of our remaining non-debugging symbols which have no match
1087 * among the module's known symbols, add them as new symbols. */
1088 hash_table_iter_init(ht_symtab
, &hti_ours
, NULL
);
1089 while ((ste
= hash_table_iter_up(&hti_ours
)))
1091 if (!(dbghelp_options
& SYMOPT_PUBLICS_ONLY
) && !ste
->used
)
1095 symt_new_function(module
, ste
->compiland
, ste
->ht_elt
.name
,
1096 ste
->addr
, 0, NULL
);
1100 struct location loc
;
1102 loc
.kind
= loc_absolute
;
1104 loc
.offset
= ste
->addr
;
1105 symt_new_global_variable(module
, ste
->compiland
, ste
->ht_elt
.name
,
1106 !ste
->is_global
, loc
, 0, NULL
);
1112 if (ste
->is_public
&& !(dbghelp_options
& SYMOPT_NO_PUBLICS
))
1114 symt_new_public(module
, ste
->compiland
, ste
->ht_elt
.name
, ste
->is_code
, ste
->addr
, 0);
1119 /******************************************************************
1122 * Try to load a debug symbol file from the given path and check
1123 * if its UUID matches the UUID of an already-mapped file. If so,
1124 * stash the file map in the "dsym" field of the file and return
1125 * TRUE. If it can't be mapped or its UUID doesn't match, return
1128 static BOOL
try_dsym(struct process
*pcs
, const WCHAR
* path
, struct macho_file_map
* fmap
)
1130 struct image_file_map dsym_ifm
;
1132 if (macho_map_file(pcs
, path
, FALSE
, &dsym_ifm
))
1134 char uuid_string
[UUID_STRING_LEN
];
1136 if (dsym_ifm
.u
.macho
.uuid
&& !memcmp(dsym_ifm
.u
.macho
.uuid
->uuid
, fmap
->uuid
->uuid
, sizeof(fmap
->uuid
->uuid
)))
1138 TRACE("found matching debug symbol file at %s\n", debugstr_w(path
));
1139 fmap
->dsym
= HeapAlloc(GetProcessHeap(), 0, sizeof(dsym_ifm
));
1140 *fmap
->dsym
= dsym_ifm
;
1144 TRACE("candidate debug symbol file at %s has wrong UUID %s; ignoring\n", debugstr_w(path
),
1145 format_uuid(dsym_ifm
.u
.macho
.uuid
->uuid
, uuid_string
));
1147 macho_unmap_file(&dsym_ifm
);
1150 TRACE("couldn't map file at %s\n", debugstr_w(path
));
1155 /******************************************************************
1158 * Search for a debugging symbols file associated with a module and
1159 * map it. First look for a .dSYM bundle next to the module file
1160 * (e.g. <path>.dSYM/Contents/Resources/DWARF/<basename of path>)
1161 * as produced by dsymutil. Next, look for a .dwarf file next to
1162 * the module file (e.g. <path>.dwarf) as produced by
1163 * "dsymutil --flat". Finally, use Spotlight to search for a
1164 * .dSYM bundle with the same UUID as the module file.
1166 static void find_and_map_dsym(struct process
*pcs
, struct module
* module
)
1168 static const WCHAR dot_dsym
[] = {'.','d','S','Y','M',0};
1169 static const WCHAR dsym_subpath
[] = {'/','C','o','n','t','e','n','t','s','/','R','e','s','o','u','r','c','e','s','/','D','W','A','R','F','/',0};
1170 static const WCHAR dot_dwarf
[] = {'.','d','w','a','r','f',0};
1171 struct macho_file_map
* fmap
= &module
->format_info
[DFI_MACHO
]->u
.macho_info
->file_map
.u
.macho
;
1175 char uuid_string
[UUID_STRING_LEN
];
1176 CFStringRef uuid_cfstring
;
1177 CFStringRef query_string
;
1178 MDQueryRef query
= NULL
;
1180 /* Without a UUID, we can't verify that any debug info file we find corresponds
1181 to this file. Better to have no debug info than incorrect debug info. */
1185 if ((p
= strrchrW(module
->module
.LoadedImageName
, '/')))
1188 p
= module
->module
.LoadedImageName
;
1189 len
= strlenW(module
->module
.LoadedImageName
) + strlenW(dot_dsym
) + strlenW(dsym_subpath
) + strlenW(p
) + 1;
1190 path
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1193 strcpyW(path
, module
->module
.LoadedImageName
);
1194 strcatW(path
, dot_dsym
);
1195 strcatW(path
, dsym_subpath
);
1198 if (try_dsym(pcs
, path
, fmap
))
1201 strcpyW(path
+ strlenW(module
->module
.LoadedImageName
), dot_dwarf
);
1203 if (try_dsym(pcs
, path
, fmap
))
1206 format_uuid(fmap
->uuid
->uuid
, uuid_string
);
1207 uuid_cfstring
= CFStringCreateWithCString(NULL
, uuid_string
, kCFStringEncodingASCII
);
1208 query_string
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("com_apple_xcode_dsym_uuids == \"%@\""), uuid_cfstring
);
1209 CFRelease(uuid_cfstring
);
1210 query
= MDQueryCreate(NULL
, query_string
, NULL
, NULL
);
1211 CFRelease(query_string
);
1212 MDQuerySetMaxCount(query
, 1);
1213 if (MDQueryExecute(query
, kMDQuerySynchronous
) && MDQueryGetResultCount(query
) >= 1)
1215 MDItemRef item
= (MDItemRef
)MDQueryGetResultAtIndex(query
, 0);
1216 CFStringRef item_path
= MDItemCopyAttribute(item
, kMDItemPath
);
1219 CFIndex item_path_len
= CFStringGetLength(item_path
);
1220 if (item_path_len
+ strlenW(dsym_subpath
) + strlenW(p
) >= len
)
1222 HeapFree(GetProcessHeap(), 0, path
);
1223 len
= item_path_len
+ strlenW(dsym_subpath
) + strlenW(p
) + 1;
1224 path
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1226 CFStringGetCharacters(item_path
, CFRangeMake(0, item_path_len
), (UniChar
*)path
);
1227 strcpyW(path
+ item_path_len
, dsym_subpath
);
1229 CFRelease(item_path
);
1231 if (try_dsym(pcs
, path
, fmap
))
1237 HeapFree(GetProcessHeap(), 0, path
);
1238 if (query
) CFRelease(query
);
1241 /******************************************************************
1242 * image_uses_split_segs
1244 * Determine if the Mach-O image loaded at a particular address in
1245 * the given process is in the dyld shared cache and therefore has
1246 * its segments mapped non-contiguously.
1248 * The image header has to be loaded from the process's memory
1249 * because the relevant flag is only set in memory, not in the file.
1251 static BOOL
image_uses_split_segs(HANDLE process
, unsigned long load_addr
)
1253 BOOL split_segs
= FALSE
;
1255 if (process
&& load_addr
)
1257 struct process
*pcs
= process_find_by_handle(process
);
1258 cpu_type_t target_cpu
= (pcs
->is_64bit
) ? CPU_TYPE_X86_64
: CPU_TYPE_X86
;
1259 uint32_t target_magic
= (pcs
->is_64bit
) ? MH_MAGIC_64
: MH_MAGIC
;
1260 struct mach_header header
;
1262 if (ReadProcessMemory(process
, (void*)load_addr
, &header
, sizeof(header
), NULL
) &&
1263 header
.magic
== target_magic
&& header
.cputype
== target_cpu
&&
1264 header
.flags
& MACHO_DYLD_IN_SHARED_CACHE
)
1273 /******************************************************************
1274 * macho_load_debug_info
1276 * Loads Mach-O debugging information from the module image file.
1278 BOOL
macho_load_debug_info(struct process
*pcs
, struct module
* module
)
1281 struct macho_debug_info mdi
;
1283 struct image_file_map
*ifm
;
1284 struct macho_file_map
*fmap
;
1286 if (module
->type
!= DMT_MACHO
|| !module
->format_info
[DFI_MACHO
]->u
.macho_info
)
1288 ERR("Bad Mach-O module '%s'\n", debugstr_w(module
->module
.LoadedImageName
));
1292 ifm
= &module
->format_info
[DFI_MACHO
]->u
.macho_info
->file_map
;
1293 fmap
= &ifm
->u
.macho
;
1295 TRACE("(%p, %p/%d)\n", module
, fmap
, fmap
->fd
);
1297 module
->module
.SymType
= SymExport
;
1299 if (!(dbghelp_options
& SYMOPT_PUBLICS_ONLY
))
1301 find_and_map_dsym(pcs
, module
);
1303 if (dwarf2_parse(module
, module
->reloc_delta
, NULL
/* FIXME: some thunks to deal with ? */,
1304 &module
->format_info
[DFI_MACHO
]->u
.macho_info
->file_map
))
1309 mdi
.module
= module
;
1310 pool_init(&mdi
.pool
, 65536);
1311 hash_table_init(&mdi
.pool
, &mdi
.ht_symtab
, 256);
1312 result
= macho_enum_load_commands(ifm
, LC_SYMTAB
, macho_parse_symtab
, &mdi
);
1315 else if (result
< 0)
1316 WARN("Couldn't correctly read stabs\n");
1318 if (!(dbghelp_options
& SYMOPT_PUBLICS_ONLY
) && fmap
->dsym
)
1320 mdi
.fmap
= &fmap
->dsym
->u
.macho
;
1321 result
= macho_enum_load_commands(fmap
->dsym
, LC_SYMTAB
, macho_parse_symtab
, &mdi
);
1324 else if (result
< 0)
1325 WARN("Couldn't correctly read stabs\n");
1328 macho_finish_stabs(module
, &mdi
.ht_symtab
);
1330 pool_destroy(&mdi
.pool
);
1334 /******************************************************************
1335 * macho_fetch_file_info
1337 * Gathers some more information for a Mach-O module from a given file
1339 BOOL
macho_fetch_file_info(HANDLE process
, const WCHAR
* name
, unsigned long load_addr
, DWORD_PTR
* base
,
1340 DWORD
* size
, DWORD
* checksum
)
1342 struct image_file_map fmap
;
1343 struct process
*pcs
;
1346 TRACE("(%s, %p, %p, %p)\n", debugstr_w(name
), base
, size
, checksum
);
1348 pcs
= process_find_by_handle(process
);
1349 if (!pcs
) return FALSE
;
1351 split_segs
= image_uses_split_segs(process
, load_addr
);
1352 if (!macho_map_file(pcs
, name
, split_segs
, &fmap
)) return FALSE
;
1353 if (base
) *base
= fmap
.u
.macho
.segs_start
;
1354 *size
= fmap
.u
.macho
.segs_size
;
1355 *checksum
= calc_crc32(fmap
.u
.macho
.fd
);
1356 macho_unmap_file(&fmap
);
1360 /******************************************************************
1361 * macho_module_remove
1363 static void macho_module_remove(struct process
* pcs
, struct module_format
* modfmt
)
1365 macho_unmap_file(&modfmt
->u
.macho_info
->file_map
);
1366 HeapFree(GetProcessHeap(), 0, modfmt
);
1370 /******************************************************************
1371 * get_dyld_image_info_address
1373 static ULONG_PTR
get_dyld_image_info_address(struct process
* pcs
)
1376 PROCESS_BASIC_INFORMATION pbi
;
1377 ULONG_PTR dyld_image_info_address
= 0;
1380 /* Get address of PEB */
1381 status
= NtQueryInformationProcess(pcs
->handle
, ProcessBasicInformation
, &pbi
, sizeof(pbi
), NULL
);
1382 if (status
== STATUS_SUCCESS
)
1384 /* Read dyld image info address from PEB */
1386 ret
= ReadProcessMemory(pcs
->handle
, &pbi
.PebBaseAddress
->Reserved
[0],
1387 &dyld_image_info_address
, sizeof(dyld_image_info_address
), NULL
);
1390 PEB32
*peb32
= (PEB32
*)pbi
.PebBaseAddress
;
1392 ret
= ReadProcessMemory(pcs
->handle
, &peb32
->Reserved
[0], &addr32
,
1393 sizeof(addr32
), NULL
);
1394 dyld_image_info_address
= addr32
;
1398 TRACE("got dyld_image_info_address %#lx from PEB %p\n",
1399 dyld_image_info_address
, pbi
.PebBaseAddress
);
1402 #ifndef __LP64__ /* No reading the symtab with nlist(3) in LP64 */
1403 if (!dyld_image_info_address
)
1405 static void* dyld_all_image_infos_addr
;
1407 /* Our next best guess is that dyld was loaded at its base address
1408 and we can find the dyld image infos address by looking up its symbol. */
1409 if (!dyld_all_image_infos_addr
)
1412 memset(nl
, 0, sizeof(nl
));
1413 nl
[0].n_un
.n_name
= (char*)"_dyld_all_image_infos";
1414 if (!nlist("/usr/lib/dyld", nl
))
1415 dyld_all_image_infos_addr
= (void*)nl
[0].n_value
;
1418 if (dyld_all_image_infos_addr
)
1420 TRACE("got dyld_image_info_address %p from /usr/lib/dyld symbol table\n",
1421 dyld_all_image_infos_addr
);
1422 dyld_image_info_address
= (ULONG_PTR
)dyld_all_image_infos_addr
;
1427 return dyld_image_info_address
;
1430 /******************************************************************
1433 * Loads the information for Mach-O module stored in 'filename'.
1434 * The module has been loaded at 'load_addr' address.
1436 * FALSE if the file cannot be found/opened or if the file doesn't
1437 * contain symbolic info (or this info cannot be read or parsed)
1440 static BOOL
macho_load_file(struct process
* pcs
, const WCHAR
* filename
,
1441 unsigned long load_addr
, struct macho_info
* macho_info
)
1445 struct image_file_map fmap
;
1447 TRACE("(%p/%p, %s, 0x%08lx, %p/0x%08x)\n", pcs
, pcs
->handle
, debugstr_w(filename
),
1448 load_addr
, macho_info
, macho_info
->flags
);
1450 split_segs
= image_uses_split_segs(pcs
->handle
, load_addr
);
1451 if (!macho_map_file(pcs
, filename
, split_segs
, &fmap
)) return FALSE
;
1453 /* Find the dynamic loader's table of images loaded into the process.
1455 if (macho_info
->flags
& MACHO_INFO_DEBUG_HEADER
)
1457 macho_info
->dbg_hdr_addr
= (unsigned long)get_dyld_image_info_address(pcs
);
1461 if (macho_info
->flags
& MACHO_INFO_MODULE
)
1463 struct macho_module_info
*macho_module_info
;
1464 struct module_format
* modfmt
=
1465 HeapAlloc(GetProcessHeap(), 0, sizeof(struct module_format
) + sizeof(struct macho_module_info
));
1466 if (!modfmt
) goto leave
;
1468 load_addr
= fmap
.u
.macho
.segs_start
;
1469 macho_info
->module
= module_new(pcs
, filename
, DMT_MACHO
, FALSE
, load_addr
,
1470 fmap
.u
.macho
.segs_size
, 0, calc_crc32(fmap
.u
.macho
.fd
));
1471 if (!macho_info
->module
)
1473 HeapFree(GetProcessHeap(), 0, modfmt
);
1476 macho_info
->module
->reloc_delta
= macho_info
->module
->module
.BaseOfImage
- fmap
.u
.macho
.segs_start
;
1477 macho_module_info
= (void*)(modfmt
+ 1);
1478 macho_info
->module
->format_info
[DFI_MACHO
] = modfmt
;
1480 modfmt
->module
= macho_info
->module
;
1481 modfmt
->remove
= macho_module_remove
;
1482 modfmt
->loc_compute
= NULL
;
1483 modfmt
->u
.macho_info
= macho_module_info
;
1485 macho_module_info
->load_addr
= load_addr
;
1487 macho_module_info
->file_map
= fmap
;
1488 reset_file_map(&fmap
);
1489 if (dbghelp_options
& SYMOPT_DEFERRED_LOADS
)
1490 macho_info
->module
->module
.SymType
= SymDeferred
;
1491 else if (!macho_load_debug_info(pcs
, macho_info
->module
))
1494 macho_info
->module
->format_info
[DFI_MACHO
]->u
.macho_info
->in_use
= 1;
1495 macho_info
->module
->format_info
[DFI_MACHO
]->u
.macho_info
->is_loader
= 0;
1496 TRACE("module = %p\n", macho_info
->module
);
1499 if (macho_info
->flags
& MACHO_INFO_NAME
)
1502 ptr
= HeapAlloc(GetProcessHeap(), 0, (lstrlenW(filename
) + 1) * sizeof(WCHAR
));
1505 strcpyW(ptr
, filename
);
1506 macho_info
->module_name
= ptr
;
1509 TRACE("module_name = %p %s\n", macho_info
->module_name
, debugstr_w(macho_info
->module_name
));
1512 macho_unmap_file(&fmap
);
1514 TRACE(" => %d\n", ret
);
1518 /******************************************************************
1519 * macho_load_file_from_path
1520 * Tries to load a Mach-O file from a set of paths (separated by ':')
1522 static BOOL
macho_load_file_from_path(struct process
* pcs
,
1523 const WCHAR
* filename
,
1524 unsigned long load_addr
,
1526 struct macho_info
* macho_info
)
1530 WCHAR
* pathW
= NULL
;
1533 TRACE("(%p/%p, %s, 0x%08lx, %s, %p)\n", pcs
, pcs
->handle
, debugstr_w(filename
), load_addr
,
1534 debugstr_a(path
), macho_info
);
1536 if (!path
) return FALSE
;
1538 len
= MultiByteToWideChar(CP_UNIXCP
, 0, path
, -1, NULL
, 0);
1539 pathW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1540 if (!pathW
) return FALSE
;
1541 MultiByteToWideChar(CP_UNIXCP
, 0, path
, -1, pathW
, len
);
1543 for (s
= pathW
; s
&& *s
; s
= (t
) ? (t
+1) : NULL
)
1545 t
= strchrW(s
, ':');
1547 fn
= HeapAlloc(GetProcessHeap(), 0, (lstrlenW(filename
) + 1 + lstrlenW(s
) + 1) * sizeof(WCHAR
));
1550 strcatW(fn
, S_SlashW
);
1551 strcatW(fn
, filename
);
1552 ret
= macho_load_file(pcs
, fn
, load_addr
, macho_info
);
1553 HeapFree(GetProcessHeap(), 0, fn
);
1555 s
= (t
) ? (t
+1) : NULL
;
1558 TRACE(" => %d\n", ret
);
1559 HeapFree(GetProcessHeap(), 0, pathW
);
1563 /******************************************************************
1564 * macho_load_file_from_dll_path
1566 * Tries to load a Mach-O file from the dll path
1568 static BOOL
macho_load_file_from_dll_path(struct process
* pcs
,
1569 const WCHAR
* filename
,
1570 unsigned long load_addr
,
1571 struct macho_info
* macho_info
)
1574 unsigned int index
= 0;
1577 TRACE("(%p/%p, %s, 0x%08lx, %p)\n", pcs
, pcs
->handle
, debugstr_w(filename
), load_addr
,
1580 while (!ret
&& (path
= wine_dll_enum_load_path( index
++ )))
1585 len
= MultiByteToWideChar(CP_UNIXCP
, 0, path
, -1, NULL
, 0);
1587 name
= HeapAlloc( GetProcessHeap(), 0,
1588 (len
+ lstrlenW(filename
) + 2) * sizeof(WCHAR
) );
1591 MultiByteToWideChar(CP_UNIXCP
, 0, path
, -1, name
, len
);
1592 strcatW( name
, S_SlashW
);
1593 strcatW( name
, filename
);
1594 ret
= macho_load_file(pcs
, name
, load_addr
, macho_info
);
1595 HeapFree( GetProcessHeap(), 0, name
);
1597 TRACE(" => %d\n", ret
);
1601 /******************************************************************
1602 * macho_search_and_load_file
1604 * Lookup a file in standard Mach-O locations, and if found, load it
1606 static BOOL
macho_search_and_load_file(struct process
* pcs
, const WCHAR
* filename
,
1607 unsigned long load_addr
,
1608 struct macho_info
* macho_info
)
1611 struct module
* module
;
1612 static const WCHAR S_libstdcPPW
[] = {'l','i','b','s','t','d','c','+','+','\0'};
1615 TRACE("(%p/%p, %s, 0x%08lx, %p)\n", pcs
, pcs
->handle
, debugstr_w(filename
), load_addr
,
1618 if (filename
== NULL
|| *filename
== '\0') return FALSE
;
1619 if ((module
= module_is_already_loaded(pcs
, filename
)))
1621 macho_info
->module
= module
;
1622 module
->format_info
[DFI_MACHO
]->u
.macho_info
->in_use
= 1;
1623 return module
->module
.SymType
;
1626 if (strstrW(filename
, S_libstdcPPW
)) return FALSE
; /* We know we can't do it */
1628 /* If has no directories, try PATH first. */
1629 if (!strchrW(filename
, '/'))
1631 ret
= macho_load_file_from_path(pcs
, filename
, load_addr
,
1632 getenv("PATH"), macho_info
);
1634 /* Try DYLD_LIBRARY_PATH, with just the filename (no directories). */
1637 if ((p
= strrchrW(filename
, '/'))) p
++;
1639 ret
= macho_load_file_from_path(pcs
, p
, load_addr
,
1640 getenv("DYLD_LIBRARY_PATH"), macho_info
);
1642 /* Try the path as given. */
1644 ret
= macho_load_file(pcs
, filename
, load_addr
, macho_info
);
1645 /* Try DYLD_FALLBACK_LIBRARY_PATH, with just the filename (no directories). */
1648 const char* fallback
= getenv("DYLD_FALLBACK_LIBRARY_PATH");
1650 fallback
= "/usr/local/lib:/lib:/usr/lib";
1651 ret
= macho_load_file_from_path(pcs
, p
, load_addr
, fallback
, macho_info
);
1653 if (!ret
&& !strchrW(filename
, '/'))
1654 ret
= macho_load_file_from_dll_path(pcs
, filename
, load_addr
, macho_info
);
1659 /******************************************************************
1660 * macho_enum_modules_internal
1662 * Enumerate Mach-O modules from a running process
1664 static BOOL
macho_enum_modules_internal(const struct process
* pcs
,
1665 const WCHAR
* main_name
,
1666 enum_modules_cb cb
, void* user
)
1668 union wine_all_image_infos image_infos
;
1669 union wine_image_info
* info_array
= NULL
;
1673 WCHAR bufstrW
[MAX_PATH
];
1676 TRACE("(%p/%p, %s, %p, %p)\n", pcs
, pcs
->handle
, debugstr_w(main_name
), cb
,
1680 len
= sizeof(image_infos
.infos64
);
1682 len
= sizeof(image_infos
.infos32
);
1683 if (!pcs
->dbg_hdr_addr
||
1684 !ReadProcessMemory(pcs
->handle
, (void*)pcs
->dbg_hdr_addr
,
1685 &image_infos
, len
, NULL
))
1689 struct dyld_all_image_infos32 temp
= image_infos
.infos32
;
1690 image_infos
.infos64
.infoArrayCount
= temp
.infoArrayCount
;
1691 image_infos
.infos64
.infoArray
= temp
.infoArray
;
1693 if (!image_infos
.infos64
.infoArray
)
1695 TRACE("Process has %u image infos at %p\n", image_infos
.infos64
.infoArrayCount
, (void*)image_infos
.infos64
.infoArray
);
1698 len
= sizeof(info_array
->info64
);
1700 len
= sizeof(info_array
->info32
);
1701 len
*= image_infos
.infos64
.infoArrayCount
;
1702 info_array
= HeapAlloc(GetProcessHeap(), 0, len
);
1704 !ReadProcessMemory(pcs
->handle
, (void*)image_infos
.infos64
.infoArray
,
1705 info_array
, len
, NULL
))
1707 TRACE("... read image infos\n");
1709 for (i
= 0; i
< image_infos
.infos64
.infoArrayCount
; i
++)
1711 struct dyld_image_info64 info
;
1713 info
= info_array
[i
].info64
;
1716 struct dyld_image_info32
*info32
= &info_array
->info32
+ i
;
1717 info
.imageLoadAddress
= info32
->imageLoadAddress
;
1718 info
.imageFilePath
= info32
->imageFilePath
;
1720 if (info
.imageFilePath
&&
1721 ReadProcessMemory(pcs
->handle
, (void*)info
.imageFilePath
, bufstr
, sizeof(bufstr
), NULL
))
1723 bufstr
[sizeof(bufstr
) - 1] = '\0';
1724 TRACE("[%d] image file %s\n", i
, debugstr_a(bufstr
));
1725 MultiByteToWideChar(CP_UNIXCP
, 0, bufstr
, -1, bufstrW
, ARRAY_SIZE(bufstrW
));
1726 if (main_name
&& !bufstrW
[0]) strcpyW(bufstrW
, main_name
);
1727 if (!cb(bufstrW
, info
.imageLoadAddress
, user
)) break;
1733 HeapFree(GetProcessHeap(), 0, info_array
);
1739 struct process
* pcs
;
1740 struct macho_info macho_info
;
1743 static BOOL
macho_enum_sync_cb(const WCHAR
* name
, unsigned long addr
, void* user
)
1745 struct macho_sync
* ms
= user
;
1747 TRACE("(%s, 0x%08lx, %p)\n", debugstr_w(name
), addr
, user
);
1748 macho_search_and_load_file(ms
->pcs
, name
, addr
, &ms
->macho_info
);
1752 /******************************************************************
1753 * macho_synchronize_module_list
1755 * Rescans the debuggee's modules list and synchronizes it with
1756 * the one from 'pcs', ie:
1757 * - if a module is in debuggee and not in pcs, it's loaded into pcs
1758 * - if a module is in pcs and not in debuggee, it's unloaded from pcs
1760 BOOL
macho_synchronize_module_list(struct process
* pcs
)
1762 struct module
* module
;
1763 struct macho_sync ms
;
1765 TRACE("(%p/%p)\n", pcs
, pcs
->handle
);
1767 for (module
= pcs
->lmodules
; module
; module
= module
->next
)
1769 if (module
->type
== DMT_MACHO
&& !module
->is_virtual
)
1770 module
->format_info
[DFI_MACHO
]->u
.macho_info
->in_use
= 0;
1774 ms
.macho_info
.flags
= MACHO_INFO_MODULE
;
1775 if (!macho_enum_modules_internal(pcs
, NULL
, macho_enum_sync_cb
, &ms
))
1778 module
= pcs
->lmodules
;
1781 if (module
->type
== DMT_MACHO
&& !module
->is_virtual
&&
1782 !module
->format_info
[DFI_MACHO
]->u
.macho_info
->in_use
&&
1783 !module
->format_info
[DFI_MACHO
]->u
.macho_info
->is_loader
)
1785 module_remove(pcs
, module
);
1786 /* restart all over */
1787 module
= pcs
->lmodules
;
1789 else module
= module
->next
;
1794 /******************************************************************
1795 * macho_search_loader
1797 * Lookup in a running Mach-O process the loader, and sets its Mach-O link
1798 * address (for accessing the list of loaded images) in pcs.
1799 * If flags is MACHO_INFO_MODULE, the module for the loader is also
1800 * added as a module into pcs.
1802 static BOOL
macho_search_loader(struct process
* pcs
, struct macho_info
* macho_info
)
1804 WCHAR
*loader
= get_wine_loader_name(pcs
);
1806 ULONG_PTR dyld_image_info_address
;
1807 union wine_all_image_infos image_infos
;
1808 union wine_image_info image_info
;
1810 char path
[PATH_MAX
];
1811 BOOL got_path
= FALSE
;
1814 len
= sizeof(image_infos
.infos64
);
1816 len
= sizeof(image_infos
.infos32
);
1817 dyld_image_info_address
= get_dyld_image_info_address(pcs
);
1818 if (dyld_image_info_address
&&
1819 ReadProcessMemory(pcs
->handle
, (void*)dyld_image_info_address
, &image_infos
, len
, NULL
))
1822 len
= sizeof(image_info
.info64
);
1825 struct dyld_all_image_infos32 temp
= image_infos
.infos32
;
1826 image_infos
.infos64
.infoArrayCount
= temp
.infoArrayCount
;
1827 image_infos
.infos64
.infoArray
= temp
.infoArray
;
1828 len
= sizeof(image_info
.info32
);
1830 if (image_infos
.infos64
.infoArray
&& image_infos
.infos64
.infoArrayCount
&&
1831 ReadProcessMemory(pcs
->handle
, (void*)image_infos
.infos64
.infoArray
, &image_info
, len
, NULL
))
1835 struct dyld_image_info32 temp
= image_info
.info32
;
1836 image_info
.info64
.imageLoadAddress
= temp
.imageLoadAddress
;
1837 image_info
.info64
.imageFilePath
= temp
.imageFilePath
;
1839 for (len
= sizeof(path
); image_info
.info64
.imageFilePath
&& len
> 0; len
/= 2)
1841 if (ReadProcessMemory(pcs
->handle
, (void*)image_info
.info64
.imageFilePath
, path
, len
, NULL
))
1845 TRACE("got executable path from target's dyld image info: %s\n", debugstr_a(path
));
1852 /* If we couldn't get the executable path from the target process, try our
1853 own. It will almost always be the same. */
1857 if (!_NSGetExecutablePath(path
, &len
))
1860 TRACE("using own executable path: %s\n", debugstr_a(path
));
1868 len
= MultiByteToWideChar(CP_UNIXCP
, 0, path
, -1, NULL
, 0);
1869 pathW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1872 MultiByteToWideChar(CP_UNIXCP
, 0, path
, -1, pathW
, len
);
1873 ret
= macho_load_file(pcs
, pathW
, 0, macho_info
);
1874 HeapFree(GetProcessHeap(), 0, pathW
);
1879 ret
= macho_search_and_load_file(pcs
, loader
, 0, macho_info
);
1884 /******************************************************************
1885 * macho_read_wine_loader_dbg_info
1887 * Try to find a decent wine executable which could have loaded the debuggee
1889 BOOL
macho_read_wine_loader_dbg_info(struct process
* pcs
)
1891 struct macho_info macho_info
;
1893 TRACE("(%p/%p)\n", pcs
, pcs
->handle
);
1894 macho_info
.flags
= MACHO_INFO_DEBUG_HEADER
| MACHO_INFO_MODULE
;
1895 if (!macho_search_loader(pcs
, &macho_info
)) return FALSE
;
1896 macho_info
.module
->format_info
[DFI_MACHO
]->u
.macho_info
->is_loader
= 1;
1897 module_set_module(macho_info
.module
, S_WineLoaderW
);
1898 return (pcs
->dbg_hdr_addr
= macho_info
.dbg_hdr_addr
) != 0;
1901 /******************************************************************
1902 * macho_enum_modules
1904 * Enumerates the Mach-O loaded modules from a running target (hProc)
1905 * This function doesn't require that someone has called SymInitialize
1906 * on this very process.
1908 BOOL
macho_enum_modules(HANDLE hProc
, enum_modules_cb cb
, void* user
)
1911 struct macho_info macho_info
;
1914 TRACE("(%p, %p, %p)\n", hProc
, cb
, user
);
1915 memset(&pcs
, 0, sizeof(pcs
));
1917 macho_info
.flags
= MACHO_INFO_DEBUG_HEADER
| MACHO_INFO_NAME
;
1918 if (!macho_search_loader(&pcs
, &macho_info
)) return FALSE
;
1919 pcs
.dbg_hdr_addr
= macho_info
.dbg_hdr_addr
;
1920 ret
= macho_enum_modules_internal(&pcs
, macho_info
.module_name
, cb
, user
);
1921 HeapFree(GetProcessHeap(), 0, (char*)macho_info
.module_name
);
1927 struct process
* pcs
;
1928 struct macho_info macho_info
;
1933 /******************************************************************
1936 * Callback for macho_load_module, used to walk the list of loaded
1939 static BOOL
macho_load_cb(const WCHAR
* name
, unsigned long addr
, void* user
)
1941 struct macho_load
* ml
= user
;
1944 TRACE("(%s, 0x%08lx, %p)\n", debugstr_w(name
), addr
, user
);
1946 /* memcmp is needed for matches when bufstr contains also version information
1947 * ml->name: libc.so, name: libc.so.6.0
1949 p
= strrchrW(name
, '/');
1951 if (!memcmp(p
, ml
->name
, lstrlenW(ml
->name
) * sizeof(WCHAR
)))
1953 ml
->ret
= macho_search_and_load_file(ml
->pcs
, name
, addr
, &ml
->macho_info
);
1959 /******************************************************************
1962 * Loads a Mach-O module and stores it in process' module list.
1963 * Also, find module real name and load address from
1964 * the real loaded modules list in pcs address space.
1966 struct module
* macho_load_module(struct process
* pcs
, const WCHAR
* name
, unsigned long addr
)
1968 struct macho_load ml
;
1970 TRACE("(%p/%p, %s, 0x%08lx)\n", pcs
, pcs
->handle
, debugstr_w(name
), addr
);
1972 ml
.macho_info
.flags
= MACHO_INFO_MODULE
;
1975 if (pcs
->dbg_hdr_addr
) /* we're debugging a live target */
1978 /* do only the lookup from the filename, not the path (as we lookup module
1979 * name in the process' loaded module list)
1981 ml
.name
= strrchrW(name
, '/');
1982 if (!ml
.name
++) ml
.name
= name
;
1985 if (!macho_enum_modules_internal(pcs
, NULL
, macho_load_cb
, &ml
))
1991 ml
.ret
= macho_search_and_load_file(pcs
, ml
.name
, addr
, &ml
.macho_info
);
1993 if (!ml
.ret
) return NULL
;
1994 assert(ml
.macho_info
.module
);
1995 return ml
.macho_info
.module
;
1998 #else /* HAVE_MACH_O_LOADER_H */
2000 BOOL
macho_find_section(struct image_file_map
* ifm
, const char* segname
, const char* sectname
, struct image_section_map
* ism
)
2005 const char* macho_map_section(struct image_section_map
* ism
)
2010 void macho_unmap_section(struct image_section_map
* ism
)
2014 DWORD_PTR
macho_get_map_rva(const struct image_section_map
* ism
)
2019 unsigned macho_get_map_size(const struct image_section_map
* ism
)
2024 BOOL
macho_synchronize_module_list(struct process
* pcs
)
2029 BOOL
macho_fetch_file_info(HANDLE process
, const WCHAR
* name
, unsigned long load_addr
, DWORD_PTR
* base
,
2030 DWORD
* size
, DWORD
* checksum
)
2035 BOOL
macho_read_wine_loader_dbg_info(struct process
* pcs
)
2040 BOOL
macho_enum_modules(HANDLE hProc
, enum_modules_cb cb
, void* user
)
2045 struct module
* macho_load_module(struct process
* pcs
, const WCHAR
* name
, unsigned long addr
)
2050 BOOL
macho_load_debug_info(struct process
*pcs
, struct module
* module
)
2054 #endif /* HAVE_MACH_O_LOADER_H */