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
30 #define WIN32_NO_STATUS
31 #include "dbghelp_private.h"
32 #include "image_private.h"
36 #define WINE_MOUNTMGR_EXTENSIONS
37 #include "ddk/mountmgr.h"
39 #include "wine/debug.h"
40 #include "wine/heap.h"
42 struct dyld_image_info32
44 UINT32 imageLoadAddress
; /* const struct mach_header* */
45 UINT32 imageFilePath
; /* const char* */
46 UINT32 imageFileModDate
; /* uintptr_t */
49 struct dyld_all_image_infos32
52 UINT32 infoArrayCount
;
53 UINT32 infoArray
; /* const struct dyld_image_info* */
56 struct dyld_image_info64
58 UINT64 imageLoadAddress
; /* const struct mach_header* */
59 UINT64 imageFilePath
; /* const char* */
60 UINT64 imageFileModDate
; /* uintptr_t */
63 struct dyld_all_image_infos64
66 UINT32 infoArrayCount
;
67 UINT64 infoArray
; /* const struct dyld_image_info* */
70 union wine_image_info
{
71 struct dyld_image_info32 info32
;
72 struct dyld_image_info64 info64
;
75 union wine_all_image_infos
{
76 struct dyld_all_image_infos32 infos32
;
77 struct dyld_all_image_infos64 infos64
;
82 UINT32 magic
; /* mach magic number identifier */
83 UINT32 cputype
; /* cpu specifier */
84 UINT32 cpusubtype
; /* machine specifier */
85 UINT32 filetype
; /* type of file */
86 UINT32 ncmds
; /* number of load commands */
87 UINT32 sizeofcmds
; /* the size of all the load commands */
88 UINT32 flags
; /* flags */
89 UINT32 reserved
; /* reserved */
92 struct macho_segment_command
94 UINT32 cmd
; /* LC_SEGMENT_64 */
95 UINT32 cmdsize
; /* includes sizeof section_64 structs */
96 char segname
[16]; /* segment name */
97 UINT64 vmaddr
; /* memory address of this segment */
98 UINT64 vmsize
; /* memory size of this segment */
99 UINT64 fileoff
; /* file offset of this segment */
100 UINT64 filesize
; /* amount to map from the file */
101 UINT32 maxprot
; /* maximum VM protection */
102 UINT32 initprot
; /* initial VM protection */
103 UINT32 nsects
; /* number of sections in segment */
104 UINT32 flags
; /* flags */
107 struct macho_segment_command32
109 UINT32 cmd
; /* LC_SEGMENT */
110 UINT32 cmdsize
; /* includes sizeof section structs */
111 char segname
[16]; /* segment name */
112 UINT32 vmaddr
; /* memory address of this segment */
113 UINT32 vmsize
; /* memory size of this segment */
114 UINT32 fileoff
; /* file offset of this segment */
115 UINT32 filesize
; /* amount to map from the file */
116 UINT32 maxprot
; /* maximum VM protection */
117 UINT32 initprot
; /* initial VM protection */
118 UINT32 nsects
; /* number of sections in segment */
119 UINT32 flags
; /* flags */
122 struct macho_symtab_command
124 UINT32 cmd
; /* LC_SYMTAB */
125 UINT32 cmdsize
; /* sizeof(struct symtab_command) */
126 UINT32 symoff
; /* symbol table offset */
127 UINT32 nsyms
; /* number of symbol table entries */
128 UINT32 stroff
; /* string table offset */
129 UINT32 strsize
; /* string table size in bytes */
132 #ifdef WORDS_BIGENDIAN
133 #define swap_ulong_be_to_host(n) (n)
135 #define swap_ulong_be_to_host(n) (RtlUlongByteSwap(n))
138 WINE_DEFAULT_DEBUG_CHANNEL(dbghelp_macho
);
141 /* Bitmask for Mach-O image header flags indicating that the image is in dyld's
142 shared cached. That implies that its segments are mapped non-contiguously.
143 This value isn't defined anywhere in headers. It's used in dyld and in
144 debuggers which support OS X as a magic number.
146 The flag also isn't set in the on-disk image file. It's only set in
148 #define MACHO_DYLD_IN_SHARED_CACHE 0x80000000
150 #define MACHO_FAT_MAGIC 0xcafebabe
151 #define MACHO_MH_MAGIC_32 0xfeedface
152 #define MACHO_MH_MAGIC_64 0xfeedfacf
154 #define MACHO_CPU_TYPE_X86 0x00000007
155 #define MACHO_CPU_TYPE_X86_64 0x01000007
157 #define MACHO_MH_EXECUTE 0x2
158 #define MACHO_MH_DYLIB 0x6
159 #define MACHO_MH_DYLINKER 0x7
160 #define MACHO_MH_BUNDLE 0x8
161 #define MACHO_MH_DSYM 0xa
163 #define MACHO_LC_SEGMENT 0x01
164 #define MACHO_LC_SYMTAB 0x02
165 #define MACHO_LC_SEGMENT_64 0x19
166 #define MACHO_LC_UUID 0x1b
168 #define MACHO_SECTION_TYPE 0x000000ff
169 #define MACHO_S_ATTR_PURE_INSTRUCTIONS 0x80000000
170 #define MACHO_S_ATTR_SOME_INSTRUCTIONS 0x00000400
172 #define UUID_STRING_LEN 37 /* 16 bytes at 2 hex digits apiece, 4 dashes, and the null terminator */
175 struct macho_module_info
177 struct image_file_map file_map
;
179 unsigned short in_use
: 1,
186 unsigned int section_index
;
189 #define MACHO_INFO_MODULE 0x0001
190 #define MACHO_INFO_NAME 0x0002
194 unsigned flags
; /* IN one (or several) of the MACHO_INFO constants */
195 struct module
* module
; /* OUT loaded module (if MACHO_INFO_MODULE is set) */
196 const WCHAR
* module_name
; /* OUT found module name (if MACHO_INFO_NAME is set) */
199 static void macho_unmap_file(struct image_file_map
* fmap
);
201 static char* format_uuid(const UINT8 uuid
[16], char out
[UUID_STRING_LEN
])
203 sprintf(out
, "%02X%02X%02X%02X-%02X%02X-%02X%02X-%02X%02X-%02X%02X%02X%02X%02X%02X",
204 uuid
[0], uuid
[1], uuid
[2], uuid
[3], uuid
[4], uuid
[5], uuid
[6], uuid
[7],
205 uuid
[8], uuid
[9], uuid
[10], uuid
[11], uuid
[12], uuid
[13], uuid
[14], uuid
[15]);
209 /******************************************************************
212 * For a range (offset & length) of a single architecture within
213 * a Mach-O file, calculate the page-aligned range of the whole file
214 * that encompasses it. For a fat binary, the architecture will
215 * itself be offset within the file, so take that into account.
217 static void macho_calc_range(const struct macho_file_map
* fmap
, ULONG_PTR offset
,
218 ULONG_PTR len
, ULONG_PTR
* out_aligned_offset
,
219 ULONG_PTR
* out_aligned_end
, ULONG_PTR
* out_misalign
)
222 ULONG_PTR file_offset
, misalign
;
224 pagemask
= sysinfo
.dwAllocationGranularity
- 1;
225 file_offset
= fmap
->arch_offset
+ offset
;
226 misalign
= file_offset
& pagemask
;
227 *out_aligned_offset
= file_offset
- misalign
;
228 *out_aligned_end
= file_offset
+ len
;
230 *out_misalign
= misalign
;
233 /******************************************************************
236 * Maps a range (offset, length in bytes) from a Mach-O file into memory
238 static const char* macho_map_range(const struct macho_file_map
* fmap
, ULONG_PTR offset
, ULONG_PTR len
,
241 ULONG_PTR misalign
, aligned_offset
, aligned_map_end
;
242 const void* aligned_ptr
;
245 TRACE("(%p/%p, 0x%08Ix, 0x%08Ix)\n", fmap
, fmap
->handle
, offset
, len
);
247 macho_calc_range(fmap
, offset
, len
, &aligned_offset
, &aligned_map_end
, &misalign
);
249 if (!(mapping
= CreateFileMappingW(fmap
->handle
, NULL
, PAGE_READONLY
, 0, 0, NULL
)))
251 ERR("map creation %p failed %lu size %Iu\n", fmap
->handle
, GetLastError(), aligned_map_end
);
254 aligned_ptr
= MapViewOfFile(mapping
, FILE_MAP_READ
, 0, aligned_offset
, aligned_map_end
- aligned_offset
);
255 CloseHandle(mapping
);
258 ERR("map failed %lu\n", GetLastError());
262 TRACE("Mapped (0x%08Ix - 0x%08Ix) to %p\n", aligned_offset
, aligned_map_end
, aligned_ptr
);
266 return (const char*)aligned_ptr
+ misalign
;
269 /******************************************************************
272 * Unmaps a range (offset, length in bytes) of a Mach-O file from memory
274 static void macho_unmap_range(const char** base
, const void** mapped
, const struct macho_file_map
* fmap
,
275 ULONG_PTR offset
, ULONG_PTR len
)
277 TRACE("(%p, %p, %p/%p, 0x%08Ix, 0x%08Ix)\n", base
, mapped
, fmap
, fmap
->handle
, offset
, len
);
279 if ((mapped
&& *mapped
!= IMAGE_NO_MAP
) || (base
&& *base
!= IMAGE_NO_MAP
))
281 ULONG_PTR misalign
, aligned_offset
, aligned_map_end
;
284 macho_calc_range(fmap
, offset
, len
, &aligned_offset
, &aligned_map_end
, &misalign
);
287 aligned_ptr
= (char*)*mapped
- misalign
;
289 aligned_ptr
= (void*)*base
;
290 if (!UnmapViewOfFile(aligned_ptr
))
291 WARN("Couldn't unmap the range\n");
293 *mapped
= IMAGE_NO_MAP
;
295 *base
= IMAGE_NO_MAP
;
299 /******************************************************************
302 * Maps two ranges (offset, length in bytes) from a Mach-O file
303 * into memory. If the two ranges overlap, use one mmap so that
304 * the munmap doesn't fragment the mapping.
306 static BOOL
macho_map_ranges(const struct macho_file_map
* fmap
,
307 ULONG_PTR offset1
, ULONG_PTR len1
,
308 ULONG_PTR offset2
, ULONG_PTR len2
,
309 const void** mapped1
, const void** mapped2
)
311 ULONG_PTR aligned_offset1
, aligned_map_end1
;
312 ULONG_PTR aligned_offset2
, aligned_map_end2
;
314 TRACE("(%p/%p, 0x%08Ix, 0x%08Ix, 0x%08Ix, 0x%08Ix, %p, %p)\n", fmap
, fmap
->handle
,
315 offset1
, len1
, offset2
, len2
, mapped1
, mapped2
);
317 macho_calc_range(fmap
, offset1
, len1
, &aligned_offset1
, &aligned_map_end1
, NULL
);
318 macho_calc_range(fmap
, offset2
, len2
, &aligned_offset2
, &aligned_map_end2
, NULL
);
320 if (aligned_map_end1
< aligned_offset2
|| aligned_map_end2
< aligned_offset1
)
322 *mapped1
= macho_map_range(fmap
, offset1
, len1
, NULL
);
323 if (*mapped1
!= IMAGE_NO_MAP
)
325 *mapped2
= macho_map_range(fmap
, offset2
, len2
, NULL
);
326 if (*mapped2
== IMAGE_NO_MAP
)
327 macho_unmap_range(NULL
, mapped1
, fmap
, offset1
, len1
);
332 if (offset1
< offset2
)
334 *mapped1
= macho_map_range(fmap
, offset1
, offset2
+ len2
- offset1
, NULL
);
335 if (*mapped1
!= IMAGE_NO_MAP
)
336 *mapped2
= (const char*)*mapped1
+ offset2
- offset1
;
340 *mapped2
= macho_map_range(fmap
, offset2
, offset1
+ len1
- offset2
, NULL
);
341 if (*mapped2
!= IMAGE_NO_MAP
)
342 *mapped1
= (const char*)*mapped2
+ offset1
- offset2
;
346 TRACE(" => %p, %p\n", *mapped1
, *mapped2
);
348 return (*mapped1
!= IMAGE_NO_MAP
) && (*mapped2
!= IMAGE_NO_MAP
);
351 /******************************************************************
354 * Unmaps two ranges (offset, length in bytes) of a Mach-O file
355 * from memory. Use for ranges which were mapped by
358 static void macho_unmap_ranges(const struct macho_file_map
* fmap
,
359 ULONG_PTR offset1
, ULONG_PTR len1
,
360 ULONG_PTR offset2
, ULONG_PTR len2
,
361 const void** mapped1
, const void** mapped2
)
363 ULONG_PTR aligned_offset1
, aligned_map_end1
;
364 ULONG_PTR aligned_offset2
, aligned_map_end2
;
366 TRACE("(%p/%p, 0x%08Ix, 0x%08Ix, 0x%08Ix, 0x%08Ix, %p/%p, %p/%p)\n", fmap
, fmap
->handle
,
367 offset1
, len1
, offset2
, len2
, mapped1
, *mapped1
, mapped2
, *mapped2
);
369 macho_calc_range(fmap
, offset1
, len1
, &aligned_offset1
, &aligned_map_end1
, NULL
);
370 macho_calc_range(fmap
, offset2
, len2
, &aligned_offset2
, &aligned_map_end2
, NULL
);
372 if (aligned_map_end1
< aligned_offset2
|| aligned_map_end2
< aligned_offset1
)
374 macho_unmap_range(NULL
, mapped1
, fmap
, offset1
, len1
);
375 macho_unmap_range(NULL
, mapped2
, fmap
, offset2
, len2
);
379 if (offset1
< offset2
)
381 macho_unmap_range(NULL
, mapped1
, fmap
, offset1
, offset2
+ len2
- offset1
);
382 *mapped2
= IMAGE_NO_MAP
;
386 macho_unmap_range(NULL
, mapped2
, fmap
, offset2
, offset1
+ len1
- offset2
);
387 *mapped1
= IMAGE_NO_MAP
;
392 /******************************************************************
395 static BOOL
macho_find_segment_section(struct image_file_map
* ifm
, const char* segname
, const char* sectname
, struct image_section_map
* ism
)
397 struct macho_file_map
* fmap
;
399 char tmp
[sizeof(fmap
->sect
[0].section
.sectname
)];
401 /* Other parts of dbghelp use section names like ".eh_frame". Mach-O uses
402 names like "__eh_frame". Convert those. */
403 if (sectname
[0] == '.')
405 lstrcpynA(tmp
, "__", sizeof(tmp
));
406 lstrcpynA(tmp
+ 2, sectname
+ 1, sizeof(tmp
) - 2);
412 fmap
= &ifm
->u
.macho
;
413 for (i
= 0; i
< fmap
->num_sections
; i
++)
415 if (!fmap
->sect
[i
].ignored
&&
416 strcmp(fmap
->sect
[i
].section
.sectname
, sectname
) == 0 &&
417 (!segname
|| strcmp(fmap
->sect
[i
].section
.segname
, segname
) == 0))
432 static BOOL
macho_find_section(struct image_file_map
* ifm
, const char* sectname
, struct image_section_map
* ism
)
434 return macho_find_segment_section(ifm
, NULL
, sectname
, ism
);
437 /******************************************************************
440 const char* macho_map_section(struct image_section_map
* ism
)
442 struct macho_file_map
* fmap
= &ism
->fmap
->u
.macho
;
444 assert(ism
->fmap
->modtype
== DMT_MACHO
);
445 if (ism
->sidx
< 0 || ism
->sidx
>= ism
->fmap
->u
.macho
.num_sections
|| fmap
->sect
[ism
->sidx
].ignored
)
448 return macho_map_range(fmap
, fmap
->sect
[ism
->sidx
].section
.offset
, fmap
->sect
[ism
->sidx
].section
.size
,
449 &fmap
->sect
[ism
->sidx
].mapped
);
452 /******************************************************************
453 * macho_unmap_section
455 void macho_unmap_section(struct image_section_map
* ism
)
457 struct macho_file_map
* fmap
= &ism
->fmap
->u
.macho
;
459 if (ism
->sidx
>= 0 && ism
->sidx
< fmap
->num_sections
&& fmap
->sect
[ism
->sidx
].mapped
!= IMAGE_NO_MAP
)
461 macho_unmap_range(&fmap
->sect
[ism
->sidx
].mapped
, NULL
, fmap
, fmap
->sect
[ism
->sidx
].section
.offset
,
462 fmap
->sect
[ism
->sidx
].section
.size
);
466 /******************************************************************
469 DWORD_PTR
macho_get_map_rva(const struct image_section_map
* ism
)
471 if (ism
->sidx
< 0 || ism
->sidx
>= ism
->fmap
->u
.macho
.num_sections
||
472 ism
->fmap
->u
.macho
.sect
[ism
->sidx
].ignored
)
474 return ism
->fmap
->u
.macho
.sect
[ism
->sidx
].section
.addr
- ism
->fmap
->u
.macho
.segs_start
;
477 /******************************************************************
480 unsigned macho_get_map_size(const struct image_section_map
* ism
)
482 if (ism
->sidx
< 0 || ism
->sidx
>= ism
->fmap
->u
.macho
.num_sections
||
483 ism
->fmap
->u
.macho
.sect
[ism
->sidx
].ignored
)
485 return ism
->fmap
->u
.macho
.sect
[ism
->sidx
].section
.size
;
488 static const struct image_file_map_ops macho_file_map_ops
=
498 /******************************************************************
499 * macho_map_load_commands
501 * Maps the load commands from a Mach-O file into memory
503 static const struct macho_load_command
* macho_map_load_commands(struct macho_file_map
* fmap
)
505 if (fmap
->load_commands
== IMAGE_NO_MAP
)
507 fmap
->load_commands
= (const struct macho_load_command
*) macho_map_range(
508 fmap
, fmap
->header_size
, fmap
->commands_size
, NULL
);
509 TRACE("Mapped load commands: %p\n", fmap
->load_commands
);
512 return fmap
->load_commands
;
515 /******************************************************************
516 * macho_unmap_load_commands
518 * Unmaps the load commands of a Mach-O file from memory
520 static void macho_unmap_load_commands(struct macho_file_map
* fmap
)
522 if (fmap
->load_commands
!= IMAGE_NO_MAP
)
524 TRACE("Unmapping load commands: %p\n", fmap
->load_commands
);
525 macho_unmap_range(NULL
, (const void**)&fmap
->load_commands
, fmap
,
526 fmap
->header_size
, fmap
->commands_size
);
530 /******************************************************************
531 * macho_next_load_command
533 * Advance to the next load command
535 static const struct macho_load_command
* macho_next_load_command(const struct macho_load_command
* lc
)
537 return (const struct macho_load_command
*)((const char*)lc
+ lc
->cmdsize
);
540 /******************************************************************
541 * macho_enum_load_commands
543 * Enumerates the load commands for a Mach-O file, selecting by
544 * the command type, calling a callback for each. If the callback
545 * returns <0, that indicates an error. If it returns >0, that means
546 * it's not interested in getting any more load commands.
547 * If this function returns <0, that's an error produced by the
548 * callback. If >=0, that's the count of load commands successfully
551 static int macho_enum_load_commands(struct image_file_map
*ifm
, unsigned cmd
,
552 int (*cb
)(struct image_file_map
*, const struct macho_load_command
*, void*),
555 struct macho_file_map
* fmap
= &ifm
->u
.macho
;
556 const struct macho_load_command
* lc
;
560 TRACE("(%p/%p, %u, %p, %p)\n", fmap
, fmap
->handle
, cmd
, cb
, user
);
562 if ((lc
= macho_map_load_commands(fmap
)) == IMAGE_NO_MAP
) return -1;
564 TRACE("%u total commands\n", fmap
->commands_count
);
566 for (i
= 0; i
< fmap
->commands_count
; i
++, lc
= macho_next_load_command(lc
))
570 if (cmd
&& cmd
!= lc
->cmd
) continue;
573 result
= cb(ifm
, lc
, user
);
574 TRACE("load_command[%d] (%p), cmd %u; callback => %d\n", i
, lc
, lc
->cmd
, result
);
575 if (result
) return (result
< 0) ? result
: count
;
581 /******************************************************************
582 * macho_count_sections
584 * Callback for macho_enum_load_commands. Counts the number of
585 * significant sections in a Mach-O file. All commands are
586 * expected to be of LC_SEGMENT[_64] type.
588 static int macho_count_sections(struct image_file_map
* ifm
, const struct macho_load_command
* lc
, void* user
)
593 if (ifm
->addr_size
== 32)
595 const struct macho_segment_command32
*sc
= (const struct macho_segment_command32
*)lc
;
596 memcpy(segname
, sc
->segname
, sizeof(segname
));
601 const struct macho_segment_command
*sc
= (const struct macho_segment_command
*)lc
;
602 memcpy(segname
, sc
->segname
, sizeof(segname
));
606 TRACE("(%p/%p, %p, %p) segment %s\n", ifm
, ifm
->u
.macho
.handle
, lc
, user
,
607 debugstr_an(segname
, sizeof(segname
)));
609 ifm
->u
.macho
.num_sections
+= nsects
;
613 /******************************************************************
614 * macho_load_section_info
616 * Callback for macho_enum_load_commands. Accumulates the address
617 * range covered by the segments of a Mach-O file and builds the
618 * section map. All commands are expected to be of LC_SEGMENT[_64] type.
620 static int macho_load_section_info(struct image_file_map
* ifm
, const struct macho_load_command
* lc
, void* user
)
622 struct macho_file_map
* fmap
= &ifm
->u
.macho
;
623 struct section_info
* info
= user
;
626 ULONG_PTR tmp
, page_mask
= sysinfo
.dwPageSize
- 1;
627 UINT64 vmaddr
, vmsize
;
630 const void *sections
;
632 if (ifm
->addr_size
== 32)
634 const struct macho_segment_command32
*sc
= (const struct macho_segment_command32
*)lc
;
637 memcpy(segname
, sc
->segname
, sizeof(segname
));
639 sections
= (const void *)(sc
+ 1);
643 const struct macho_segment_command
*sc
= (const struct macho_segment_command
*)lc
;
646 memcpy(segname
, sc
->segname
, sizeof(segname
));
648 sections
= (const void *)(sc
+ 1);
651 TRACE("(%p/%p, %p, %p) before: 0x%08Ix - 0x%08Ix\n", fmap
, fmap
->handle
, lc
, user
,
652 (ULONG_PTR
)fmap
->segs_start
, (ULONG_PTR
)fmap
->segs_size
);
653 TRACE("Segment command vm: 0x%08Ix - 0x%08Ix\n", (ULONG_PTR
)vmaddr
,
654 (ULONG_PTR
)(vmaddr
+ vmsize
));
656 /* Images in the dyld shared cache have their segments mapped non-contiguously.
657 We don't know how to properly locate any of the segments other than __TEXT,
659 ignore
= (info
->split_segs
&& strcmp(segname
, "__TEXT"));
661 if (!strncmp(segname
, "WINE_", 5))
662 TRACE("Ignoring special Wine segment %s\n", debugstr_an(segname
, sizeof(segname
)));
663 else if (!strncmp(segname
, "__PAGEZERO", 10))
664 TRACE("Ignoring __PAGEZERO segment\n");
666 TRACE("Ignoring %s segment because image has split segments\n", segname
);
669 /* If this segment starts before previously-known earliest, record new earliest. */
670 if (vmaddr
< fmap
->segs_start
)
671 fmap
->segs_start
= vmaddr
;
673 /* If this segment extends beyond previously-known furthest, record new furthest. */
674 tmp
= (vmaddr
+ vmsize
+ page_mask
) & ~page_mask
;
675 if (fmap
->segs_size
< tmp
) fmap
->segs_size
= tmp
;
677 TRACE("after: 0x%08Ix - 0x%08Ix\n", (ULONG_PTR
)fmap
->segs_start
, (ULONG_PTR
)fmap
->segs_size
);
680 for (i
= 0; i
< nsects
; i
++)
682 if (ifm
->addr_size
== 32)
684 const struct macho_section32
*section
= &((const struct macho_section32
*)sections
)[i
];
685 memcpy(fmap
->sect
[info
->section_index
].section
.sectname
, section
->sectname
, sizeof(section
->sectname
));
686 memcpy(fmap
->sect
[info
->section_index
].section
.segname
, section
->segname
, sizeof(section
->segname
));
687 fmap
->sect
[info
->section_index
].section
.addr
= section
->addr
;
688 fmap
->sect
[info
->section_index
].section
.size
= section
->size
;
689 fmap
->sect
[info
->section_index
].section
.offset
= section
->offset
;
690 fmap
->sect
[info
->section_index
].section
.align
= section
->align
;
691 fmap
->sect
[info
->section_index
].section
.reloff
= section
->reloff
;
692 fmap
->sect
[info
->section_index
].section
.nreloc
= section
->nreloc
;
693 fmap
->sect
[info
->section_index
].section
.flags
= section
->flags
;
696 fmap
->sect
[info
->section_index
].section
= ((const struct macho_section
*)sections
)[i
];
698 fmap
->sect
[info
->section_index
].mapped
= IMAGE_NO_MAP
;
699 fmap
->sect
[info
->section_index
].ignored
= ignore
;
700 info
->section_index
++;
706 /******************************************************************
709 * Callback for macho_enum_load_commands. Records the UUID load
710 * command of a Mach-O file.
712 static int find_uuid(struct image_file_map
* ifm
, const struct macho_load_command
* lc
, void* user
)
714 ifm
->u
.macho
.uuid
= (const struct macho_uuid_command
*)lc
;
718 /******************************************************************
721 static inline void reset_file_map(struct image_file_map
* ifm
)
723 struct macho_file_map
* fmap
= &ifm
->u
.macho
;
725 fmap
->handle
= INVALID_HANDLE_VALUE
;
727 fmap
->load_commands
= IMAGE_NO_MAP
;
729 fmap
->num_sections
= 0;
733 /******************************************************************
736 * Maps a Mach-O file into memory (and checks it's a real Mach-O file)
738 static BOOL
macho_map_file(struct process
*pcs
, const WCHAR
*filenameW
,
739 BOOL split_segs
, struct image_file_map
* ifm
)
741 struct macho_file_map
* fmap
= &ifm
->u
.macho
;
742 struct macho_header mach_header
;
745 struct section_info info
;
747 UINT32 target_cpu
= (pcs
->is_64bit
) ? MACHO_CPU_TYPE_X86_64
: MACHO_CPU_TYPE_X86
;
748 UINT32 target_magic
= (pcs
->is_64bit
) ? MACHO_MH_MAGIC_64
: MACHO_MH_MAGIC_32
;
749 UINT32 target_cmd
= (pcs
->is_64bit
) ? MACHO_LC_SEGMENT_64
: MACHO_LC_SEGMENT
;
754 UINT32 magic
; /* FAT_MAGIC or FAT_MAGIC_64 */
755 UINT32 nfat_arch
; /* number of structs that follow */
758 TRACE("(%s, %p)\n", debugstr_w(filenameW
), fmap
);
762 ifm
->modtype
= DMT_MACHO
;
763 ifm
->ops
= &macho_file_map_ops
;
764 ifm
->alternate
= NULL
;
765 ifm
->addr_size
= (pcs
->is_64bit
) ? 64 : 32;
766 fmap
->header_size
= (pcs
->is_64bit
) ? sizeof(struct macho_header
) : FIELD_OFFSET(struct macho_header
, reserved
);
768 if (!(filename
= get_dos_file_name(filenameW
))) return FALSE
;
770 /* Now open the file, so that we can map it. */
771 fmap
->handle
= CreateFileW(filename
, GENERIC_READ
, FILE_SHARE_READ
, NULL
, OPEN_EXISTING
, 0, NULL
);
772 if (fmap
->handle
== INVALID_HANDLE_VALUE
)
774 TRACE("failed to open file %s: %d\n", debugstr_w(filename
), errno
);
778 if (!ReadFile(fmap
->handle
, &fat_header
, sizeof(fat_header
), &bytes_read
, NULL
) || bytes_read
!= sizeof(fat_header
))
780 TRACE("failed to read fat header: %lu\n", GetLastError());
783 TRACE("... got possible fat header\n");
785 /* Fat header is always in big-endian order. */
786 if (swap_ulong_be_to_host(fat_header
.magic
) == MACHO_FAT_MAGIC
)
788 int narch
= swap_ulong_be_to_host(fat_header
.nfat_arch
);
789 for (i
= 0; i
< narch
; i
++)
793 UINT32 cputype
; /* cpu specifier (int) */
794 UINT32 cpusubtype
; /* machine specifier (int) */
795 UINT32 offset
; /* file offset to this object file */
796 UINT32 size
; /* size of this object file */
797 UINT32 align
; /* alignment as a power of 2 */
800 if (!ReadFile(fmap
->handle
, &fat_arch
, sizeof(fat_arch
), &bytes_read
, NULL
) || bytes_read
!= sizeof(fat_arch
))
802 if (swap_ulong_be_to_host(fat_arch
.cputype
) == target_cpu
)
804 fmap
->arch_offset
= swap_ulong_be_to_host(fat_arch
.offset
);
808 if (i
>= narch
) goto done
;
809 TRACE("... found target arch (%d)\n", target_cpu
);
813 fmap
->arch_offset
= 0;
814 TRACE("... not a fat header\n");
817 /* Individual architecture (standalone or within a fat file) is in its native byte order. */
818 SetFilePointer(fmap
->handle
, fmap
->arch_offset
, 0, FILE_BEGIN
);
819 if (!ReadFile(fmap
->handle
, &mach_header
, fmap
->header_size
, &bytes_read
, NULL
)
820 || bytes_read
!= fmap
->header_size
)
822 TRACE("... got possible Mach header\n");
823 /* and check for a Mach-O header */
824 if (mach_header
.magic
!= target_magic
|| mach_header
.cputype
!= target_cpu
) goto done
;
825 fmap
->commands_size
= mach_header
.sizeofcmds
;
826 fmap
->commands_count
= mach_header
.ncmds
;
827 /* Make sure the file type is one of the ones we expect. */
828 switch (mach_header
.filetype
)
830 case MACHO_MH_EXECUTE
:
832 case MACHO_MH_DYLINKER
:
833 case MACHO_MH_BUNDLE
:
839 TRACE("... verified Mach header\n");
841 fmap
->num_sections
= 0;
842 if (macho_enum_load_commands(ifm
, target_cmd
, macho_count_sections
, NULL
) < 0)
844 TRACE("%d sections\n", fmap
->num_sections
);
846 fmap
->sect
= HeapAlloc(GetProcessHeap(), 0, fmap
->num_sections
* sizeof(fmap
->sect
[0]));
851 fmap
->segs_start
= ~0L;
853 info
.split_segs
= split_segs
;
854 info
.section_index
= 0;
855 if (macho_enum_load_commands(ifm
, target_cmd
, macho_load_section_info
, &info
) < 0)
857 fmap
->num_sections
= 0;
861 fmap
->segs_size
-= fmap
->segs_start
;
862 TRACE("segs_start: 0x%08Ix, segs_size: 0x%08Ix\n", (ULONG_PTR
)fmap
->segs_start
,
863 (ULONG_PTR
)fmap
->segs_size
);
865 if (macho_enum_load_commands(ifm
, MACHO_LC_UUID
, find_uuid
, NULL
) < 0)
869 char uuid_string
[UUID_STRING_LEN
];
870 TRACE("UUID %s\n", format_uuid(fmap
->uuid
->uuid
, uuid_string
));
873 TRACE("no UUID found\n");
878 macho_unmap_file(ifm
);
879 HeapFree(GetProcessHeap(), 0, filename
);
883 /******************************************************************
886 * Unmaps a Mach-O file from memory (previously mapped with macho_map_file)
888 static void macho_unmap_file(struct image_file_map
* ifm
)
890 struct image_file_map
* cursor
;
892 TRACE("(%p/%p)\n", ifm
, ifm
->u
.macho
.handle
);
897 struct image_file_map
* next
;
899 if (ifm
->u
.macho
.handle
!= INVALID_HANDLE_VALUE
)
901 struct image_section_map ism
;
904 for (ism
.sidx
= 0; ism
.sidx
< ifm
->u
.macho
.num_sections
; ism
.sidx
++)
905 macho_unmap_section(&ism
);
907 HeapFree(GetProcessHeap(), 0, ifm
->u
.macho
.sect
);
908 macho_unmap_load_commands(&ifm
->u
.macho
);
909 CloseHandle(ifm
->u
.macho
.handle
);
910 ifm
->u
.macho
.handle
= INVALID_HANDLE_VALUE
;
913 next
= cursor
->u
.macho
.dsym
;
915 HeapFree(GetProcessHeap(), 0, cursor
);
920 /******************************************************************
923 * Checks if a section, identified by sectidx which is a 1-based
924 * index into the sections of all segments, in order of load
925 * commands, contains code.
927 static BOOL
macho_sect_is_code(struct macho_file_map
* fmap
, unsigned char sectidx
)
931 TRACE("(%p/%p, %u)\n", fmap
, fmap
->handle
, sectidx
);
933 if (!sectidx
) return FALSE
;
935 sectidx
--; /* convert from 1-based to 0-based */
936 if (sectidx
>= fmap
->num_sections
|| fmap
->sect
[sectidx
].ignored
) return FALSE
;
938 ret
= (!(fmap
->sect
[sectidx
].section
.flags
& MACHO_SECTION_TYPE
) &&
939 (fmap
->sect
[sectidx
].section
.flags
& (MACHO_S_ATTR_PURE_INSTRUCTIONS
| MACHO_S_ATTR_SOME_INSTRUCTIONS
)));
940 TRACE("-> %d\n", ret
);
946 struct hash_table_elt ht_elt
;
947 struct symt_compiland
* compiland
;
949 unsigned char is_code
:1,
955 struct macho_debug_info
957 struct macho_file_map
* fmap
;
958 struct module
* module
;
960 struct hash_table ht_symtab
;
963 /******************************************************************
966 * Callback for stabs_parse. Collect symbol definitions.
968 static void macho_stabs_def_cb(struct module
* module
, ULONG_PTR load_offset
,
969 const char* name
, ULONG_PTR offset
,
970 BOOL is_public
, BOOL is_global
, unsigned char sectidx
,
971 struct symt_compiland
* compiland
, void* user
)
973 struct macho_debug_info
* mdi
= user
;
974 struct symtab_elt
* ste
;
976 TRACE("(%p, 0x%08Ix, %s, 0x%08Ix, %d, %d, %u, %p, %p/%p/%p)\n", module
, load_offset
,
977 debugstr_a(name
), offset
, is_public
, is_global
, sectidx
,
978 compiland
, mdi
, mdi
->fmap
, mdi
->fmap
->handle
);
980 /* Defer the creation of new non-debugging symbols until after we've
981 * finished parsing the stabs. */
982 ste
= pool_alloc(&mdi
->pool
, sizeof(*ste
));
983 ste
->ht_elt
.name
= pool_strdup(&mdi
->pool
, name
);
984 ste
->compiland
= compiland
;
985 ste
->addr
= load_offset
+ offset
;
986 ste
->is_code
= !!macho_sect_is_code(mdi
->fmap
, sectidx
);
987 ste
->is_public
= !!is_public
;
988 ste
->is_global
= !!is_global
;
990 hash_table_add(&mdi
->ht_symtab
, &ste
->ht_elt
);
993 /******************************************************************
996 * Callback for macho_enum_load_commands. Processes the LC_SYMTAB
997 * load commands from the Mach-O file.
999 static int macho_parse_symtab(struct image_file_map
* ifm
,
1000 const struct macho_load_command
* lc
, void* user
)
1002 struct macho_file_map
* fmap
= &ifm
->u
.macho
;
1003 const struct macho_symtab_command
* sc
= (const struct macho_symtab_command
*)lc
;
1004 struct macho_debug_info
* mdi
= user
;
1005 const char* stabstr
;
1007 size_t stabsize
= (ifm
->addr_size
== 32) ? sizeof(struct stab_nlist
) : sizeof(struct macho64_nlist
);
1010 TRACE("(%p/%p, %p, %p) %u syms at 0x%08x, strings 0x%08x - 0x%08x\n", fmap
, fmap
->handle
, lc
,
1011 user
, sc
->nsyms
, sc
->symoff
, sc
->stroff
, sc
->stroff
+ sc
->strsize
);
1013 if (!macho_map_ranges(fmap
, sc
->symoff
, sc
->nsyms
* stabsize
,
1014 sc
->stroff
, sc
->strsize
, (const void**)&stab
, (const void**)&stabstr
))
1017 if (!stabs_parse(mdi
->module
,
1018 mdi
->module
->format_info
[DFI_MACHO
]->u
.macho_info
->load_addr
- fmap
->segs_start
,
1019 stab
, sc
->nsyms
, stabsize
,
1020 stabstr
, sc
->strsize
, macho_stabs_def_cb
, mdi
))
1023 macho_unmap_ranges(fmap
, sc
->symoff
, sc
->nsyms
* stabsize
,
1024 sc
->stroff
, sc
->strsize
, (const void**)&stab
, (const void**)&stabstr
);
1029 /******************************************************************
1030 * macho_finish_stabs
1032 * Integrate the non-debugging symbols we've gathered into the
1033 * symbols that were generated during stabs parsing.
1035 static void macho_finish_stabs(struct module
* module
, struct hash_table
* ht_symtab
)
1037 struct hash_table_iter hti_ours
;
1038 struct symtab_elt
* ste
;
1039 BOOL adjusted
= FALSE
;
1041 TRACE("(%p, %p)\n", module
, ht_symtab
);
1043 /* For each of our non-debugging symbols, see if it can provide some
1044 * missing details to one of the module's known symbols. */
1045 hash_table_iter_init(ht_symtab
, &hti_ours
, NULL
);
1046 while ((ste
= hash_table_iter_up(&hti_ours
)))
1048 struct hash_table_iter hti_modules
;
1050 struct symt_ht
* sym
;
1051 struct symt_function
* func
;
1052 struct symt_data
* data
;
1054 hash_table_iter_init(&module
->ht_symbols
, &hti_modules
, ste
->ht_elt
.name
);
1055 while ((ptr
= hash_table_iter_up(&hti_modules
)))
1057 sym
= CONTAINING_RECORD(ptr
, struct symt_ht
, hash_elt
);
1059 if (strcmp(sym
->hash_elt
.name
, ste
->ht_elt
.name
))
1062 switch (sym
->symt
.tag
)
1064 case SymTagFunction
:
1065 func
= (struct symt_function
*)sym
;
1066 if (func
->address
== module
->format_info
[DFI_MACHO
]->u
.macho_info
->load_addr
)
1068 TRACE("Adjusting function %p/%s!%s from 0x%08Ix to 0x%08Ix\n", func
,
1069 debugstr_w(module
->modulename
), sym
->hash_elt
.name
,
1070 func
->address
, ste
->addr
);
1071 func
->address
= ste
->addr
;
1074 if (func
->address
== ste
->addr
)
1078 data
= (struct symt_data
*)sym
;
1082 case DataIsFileStatic
:
1083 if (data
->u
.var
.offset
== module
->format_info
[DFI_MACHO
]->u
.macho_info
->load_addr
)
1085 TRACE("Adjusting data symbol %p/%s!%s from 0x%08Ix to 0x%08Ix\n",
1086 data
, debugstr_w(module
->modulename
), sym
->hash_elt
.name
,
1087 data
->u
.var
.offset
, ste
->addr
);
1088 data
->u
.var
.offset
= ste
->addr
;
1091 if (data
->u
.var
.offset
== ste
->addr
)
1093 enum DataKind new_kind
;
1095 new_kind
= ste
->is_global
? DataIsGlobal
: DataIsFileStatic
;
1096 if (data
->kind
!= new_kind
)
1098 WARN("Changing kind for %p/%s!%s from %d to %d\n", sym
,
1099 debugstr_w(module
->modulename
), sym
->hash_elt
.name
,
1100 (int)data
->kind
, (int)new_kind
);
1101 data
->kind
= new_kind
;
1111 TRACE("Ignoring tag %u\n", sym
->symt
.tag
);
1119 /* since we may have changed some addresses, mark the module to be resorted */
1120 module
->sortlist_valid
= FALSE
;
1123 /* Mark any of our non-debugging symbols which fall on an already-used
1124 * address as "used". This allows us to skip them in the next loop,
1125 * below. We do this in separate loops because symt_new_* marks the
1126 * list as needing sorting and symt_find_nearest sorts if needed,
1127 * causing thrashing. */
1128 if (!(dbghelp_options
& SYMOPT_PUBLICS_ONLY
))
1130 hash_table_iter_init(ht_symtab
, &hti_ours
, NULL
);
1131 while ((ste
= hash_table_iter_up(&hti_ours
)))
1133 struct symt_ht
* sym
;
1136 if (ste
->used
) continue;
1138 sym
= symt_find_nearest(module
, ste
->addr
);
1140 symt_get_address(&sym
->symt
, &addr
);
1141 if (sym
&& ste
->addr
== addr
)
1148 /* If neither symbol has a correct size (ours never does), we
1149 * consider them both to be markers. No warning is needed in
1151 * Also, we check that we don't have two symbols, one local, the other
1152 * global, which is legal.
1154 symt_get_info(module
, &sym
->symt
, TI_GET_LENGTH
, &size
);
1155 symt_get_info(module
, &sym
->symt
, TI_GET_DATAKIND
, &kind
);
1156 if (size
&& kind
== (ste
->is_global
? DataIsGlobal
: DataIsFileStatic
))
1157 FIXME("Duplicate in %s: %s<%08Ix> %s<%I64x-%I64x>\n",
1158 debugstr_w(module
->modulename
),
1159 ste
->ht_elt
.name
, ste
->addr
,
1166 /* For any of our remaining non-debugging symbols which have no match
1167 * among the module's known symbols, add them as new symbols. */
1168 hash_table_iter_init(ht_symtab
, &hti_ours
, NULL
);
1169 while ((ste
= hash_table_iter_up(&hti_ours
)))
1171 if (!(dbghelp_options
& SYMOPT_PUBLICS_ONLY
) && !ste
->used
)
1175 symt_new_function(module
, ste
->compiland
, ste
->ht_elt
.name
,
1176 ste
->addr
, 0, NULL
);
1180 struct location loc
;
1182 loc
.kind
= loc_absolute
;
1184 loc
.offset
= ste
->addr
;
1185 symt_new_global_variable(module
, ste
->compiland
, ste
->ht_elt
.name
,
1186 !ste
->is_global
, loc
, 0, NULL
);
1192 if (ste
->is_public
&& !(dbghelp_options
& SYMOPT_NO_PUBLICS
))
1194 symt_new_public(module
, ste
->compiland
, ste
->ht_elt
.name
, ste
->is_code
, ste
->addr
, 0);
1199 /******************************************************************
1202 * Try to load a debug symbol file from the given path and check
1203 * if its UUID matches the UUID of an already-mapped file. If so,
1204 * stash the file map in the "dsym" field of the file and return
1205 * TRUE. If it can't be mapped or its UUID doesn't match, return
1208 static BOOL
try_dsym(struct process
*pcs
, const WCHAR
* path
, struct macho_file_map
* fmap
)
1210 struct image_file_map dsym_ifm
;
1212 if (macho_map_file(pcs
, path
, FALSE
, &dsym_ifm
))
1214 char uuid_string
[UUID_STRING_LEN
];
1216 if (dsym_ifm
.u
.macho
.uuid
&& !memcmp(dsym_ifm
.u
.macho
.uuid
->uuid
, fmap
->uuid
->uuid
, sizeof(fmap
->uuid
->uuid
)))
1218 TRACE("found matching debug symbol file at %s\n", debugstr_w(path
));
1219 fmap
->dsym
= HeapAlloc(GetProcessHeap(), 0, sizeof(dsym_ifm
));
1220 *fmap
->dsym
= dsym_ifm
;
1224 TRACE("candidate debug symbol file at %s has wrong UUID %s; ignoring\n", debugstr_w(path
),
1225 format_uuid(dsym_ifm
.u
.macho
.uuid
->uuid
, uuid_string
));
1227 macho_unmap_file(&dsym_ifm
);
1230 TRACE("couldn't map file at %s\n", debugstr_w(path
));
1235 static const WCHAR dsym_subpath
[] = L
"'\\Contents\\Resources\\DWARF\\";
1237 static WCHAR
*query_dsym(const GUID
*uuid
, const WCHAR
*filename
)
1239 WCHAR
*dos_name
= NULL
, *ret
= NULL
;
1243 mgr
= CreateFileW(MOUNTMGR_DOS_DEVICE_NAME
, GENERIC_READ
|GENERIC_WRITE
, FILE_SHARE_READ
|FILE_SHARE_WRITE
, NULL
,
1244 OPEN_EXISTING
, 0, 0);
1245 if (mgr
== INVALID_HANDLE_VALUE
) return NULL
;
1249 char *buf
= malloc( size
);
1250 if (DeviceIoControl( mgr
, IOCTL_MOUNTMGR_QUERY_SYMBOL_FILE
, (void*)uuid
, sizeof(*uuid
),
1251 buf
, size
, NULL
, NULL
))
1253 dos_name
= wine_get_dos_file_name( buf
);
1258 if (GetLastError() != ERROR_MORE_DATA
) break;
1264 if (!dos_name
) return NULL
;
1266 if ((ret
= HeapAlloc( GetProcessHeap(), 0,
1267 sizeof(dsym_subpath
) + (lstrlenW(dos_name
) + lstrlenW(filename
)) * sizeof(WCHAR
))))
1269 wcscpy( ret
, dos_name
);
1270 wcscat( ret
, dsym_subpath
);
1271 wcscat( ret
, filename
);
1273 HeapFree( GetProcessHeap(), 0, dos_name
);
1277 /******************************************************************
1280 * Search for a debugging symbols file associated with a module and
1281 * map it. First look for a .dSYM bundle next to the module file
1282 * (e.g. <path>.dSYM/Contents/Resources/DWARF/<basename of path>)
1283 * as produced by dsymutil. Next, look for a .dwarf file next to
1284 * the module file (e.g. <path>.dwarf) as produced by
1285 * "dsymutil --flat". Finally, use Spotlight to search for a
1286 * .dSYM bundle with the same UUID as the module file.
1288 static void find_and_map_dsym(struct process
*pcs
, struct module
* module
)
1290 struct macho_file_map
* fmap
= &module
->format_info
[DFI_MACHO
]->u
.macho_info
->file_map
.u
.macho
;
1295 /* Without a UUID, we can't verify that any debug info file we find corresponds
1296 to this file. Better to have no debug info than incorrect debug info. */
1300 p
= file_name(module
->module
.LoadedImageName
);
1301 len
= lstrlenW(module
->module
.LoadedImageName
) + lstrlenW(L
".dSYM") + lstrlenW(dsym_subpath
) + lstrlenW(p
) + 1;
1302 path
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1305 lstrcpyW(path
, module
->module
.LoadedImageName
);
1306 lstrcatW(path
, L
".dSYM");
1307 lstrcatW(path
, dsym_subpath
);
1310 if (try_dsym(pcs
, path
, fmap
))
1313 lstrcpyW(path
+ lstrlenW(module
->module
.LoadedImageName
), L
".dwarf");
1315 if (try_dsym(pcs
, path
, fmap
))
1318 HeapFree(GetProcessHeap(), 0, path
);
1319 if ((path
= query_dsym((const GUID
*)fmap
->uuid
->uuid
, p
))) try_dsym(pcs
, path
, fmap
);
1322 HeapFree(GetProcessHeap(), 0, path
);
1325 /******************************************************************
1326 * image_uses_split_segs
1328 * Determine if the Mach-O image loaded at a particular address in
1329 * the given process is in the dyld shared cache and therefore has
1330 * its segments mapped non-contiguously.
1332 * The image header has to be loaded from the process's memory
1333 * because the relevant flag is only set in memory, not in the file.
1335 static BOOL
image_uses_split_segs(struct process
* process
, ULONG_PTR load_addr
)
1337 BOOL split_segs
= FALSE
;
1341 UINT32 target_cpu
= (process
->is_64bit
) ? MACHO_CPU_TYPE_X86_64
: MACHO_CPU_TYPE_X86
;
1342 UINT32 target_magic
= (process
->is_64bit
) ? MACHO_MH_MAGIC_64
: MACHO_MH_MAGIC_32
;
1343 struct macho_header header
;
1345 if (read_process_memory(process
, load_addr
, &header
, FIELD_OFFSET(struct macho_header
, reserved
)) &&
1346 header
.magic
== target_magic
&& header
.cputype
== target_cpu
&&
1347 header
.flags
& MACHO_DYLD_IN_SHARED_CACHE
)
1356 /******************************************************************
1357 * macho_load_debug_info
1359 * Loads Mach-O debugging information from the module image file.
1361 static BOOL
macho_load_debug_info(struct process
*pcs
, struct module
* module
)
1364 struct macho_debug_info mdi
;
1366 struct image_file_map
*ifm
;
1367 struct macho_file_map
*fmap
;
1369 if (module
->type
!= DMT_MACHO
|| !module
->format_info
[DFI_MACHO
]->u
.macho_info
)
1371 ERR("Bad Mach-O module '%s'\n", debugstr_w(module
->module
.LoadedImageName
));
1375 ifm
= &module
->format_info
[DFI_MACHO
]->u
.macho_info
->file_map
;
1376 fmap
= &ifm
->u
.macho
;
1378 TRACE("(%p, %p/%p)\n", module
, fmap
, fmap
->handle
);
1380 module
->module
.SymType
= SymExport
;
1382 if (!(dbghelp_options
& SYMOPT_PUBLICS_ONLY
))
1384 find_and_map_dsym(pcs
, module
);
1386 if (dwarf2_parse(module
, module
->reloc_delta
, NULL
/* FIXME: some thunks to deal with ? */,
1387 &module
->format_info
[DFI_MACHO
]->u
.macho_info
->file_map
))
1392 mdi
.module
= module
;
1393 pool_init(&mdi
.pool
, 65536);
1394 hash_table_init(&mdi
.pool
, &mdi
.ht_symtab
, 256);
1395 result
= macho_enum_load_commands(ifm
, MACHO_LC_SYMTAB
, macho_parse_symtab
, &mdi
);
1398 else if (result
< 0)
1399 WARN("Couldn't correctly read stabs\n");
1401 if (!(dbghelp_options
& SYMOPT_PUBLICS_ONLY
) && fmap
->dsym
)
1403 mdi
.fmap
= &fmap
->dsym
->u
.macho
;
1404 result
= macho_enum_load_commands(fmap
->dsym
, MACHO_LC_SYMTAB
, macho_parse_symtab
, &mdi
);
1407 else if (result
< 0)
1408 WARN("Couldn't correctly read stabs\n");
1411 macho_finish_stabs(module
, &mdi
.ht_symtab
);
1413 pool_destroy(&mdi
.pool
);
1417 /******************************************************************
1418 * macho_fetch_file_info
1420 * Gathers some more information for a Mach-O module from a given file
1422 static BOOL
macho_fetch_file_info(struct process
* process
, const WCHAR
* name
, ULONG_PTR load_addr
, DWORD_PTR
* base
,
1423 DWORD
* size
, DWORD
* checksum
)
1425 struct image_file_map fmap
;
1428 TRACE("(%s, %p, %p, %p)\n", debugstr_w(name
), base
, size
, checksum
);
1430 split_segs
= image_uses_split_segs(process
, load_addr
);
1431 if (!macho_map_file(process
, name
, split_segs
, &fmap
)) return FALSE
;
1432 if (base
) *base
= fmap
.u
.macho
.segs_start
;
1433 *size
= fmap
.u
.macho
.segs_size
;
1434 *checksum
= calc_crc32(fmap
.u
.macho
.handle
);
1435 macho_unmap_file(&fmap
);
1439 /******************************************************************
1440 * macho_module_remove
1442 static void macho_module_remove(struct process
* pcs
, struct module_format
* modfmt
)
1444 macho_unmap_file(&modfmt
->u
.macho_info
->file_map
);
1445 HeapFree(GetProcessHeap(), 0, modfmt
);
1448 /******************************************************************
1451 * Loads the information for Mach-O module stored in 'filename'.
1452 * The module has been loaded at 'load_addr' address.
1454 * FALSE if the file cannot be found/opened or if the file doesn't
1455 * contain symbolic info (or this info cannot be read or parsed)
1458 static BOOL
macho_load_file(struct process
* pcs
, const WCHAR
* filename
,
1459 ULONG_PTR load_addr
, struct macho_info
* macho_info
)
1463 struct image_file_map fmap
;
1465 TRACE("(%p/%p, %s, 0x%08Ix, %p/0x%08x)\n", pcs
, pcs
->handle
, debugstr_w(filename
),
1466 load_addr
, macho_info
, macho_info
->flags
);
1468 split_segs
= image_uses_split_segs(pcs
, load_addr
);
1469 if (!macho_map_file(pcs
, filename
, split_segs
, &fmap
)) return FALSE
;
1471 if (macho_info
->flags
& MACHO_INFO_MODULE
)
1473 struct macho_module_info
*macho_module_info
;
1474 struct module_format
* modfmt
=
1475 HeapAlloc(GetProcessHeap(), 0, sizeof(struct module_format
) + sizeof(struct macho_module_info
));
1476 if (!modfmt
) goto leave
;
1478 load_addr
= fmap
.u
.macho
.segs_start
;
1479 macho_info
->module
= module_new(pcs
, filename
, DMT_MACHO
, FALSE
, load_addr
,
1480 fmap
.u
.macho
.segs_size
, 0, calc_crc32(fmap
.u
.macho
.handle
),
1481 IMAGE_FILE_MACHINE_UNKNOWN
);
1482 if (!macho_info
->module
)
1484 HeapFree(GetProcessHeap(), 0, modfmt
);
1487 macho_info
->module
->reloc_delta
= macho_info
->module
->module
.BaseOfImage
- fmap
.u
.macho
.segs_start
;
1488 macho_module_info
= (void*)(modfmt
+ 1);
1489 macho_info
->module
->format_info
[DFI_MACHO
] = modfmt
;
1491 modfmt
->module
= macho_info
->module
;
1492 modfmt
->remove
= macho_module_remove
;
1493 modfmt
->loc_compute
= NULL
;
1494 modfmt
->u
.macho_info
= macho_module_info
;
1496 macho_module_info
->load_addr
= load_addr
;
1498 macho_module_info
->file_map
= fmap
;
1499 reset_file_map(&fmap
);
1501 macho_info
->module
->format_info
[DFI_MACHO
]->u
.macho_info
->in_use
= 1;
1502 macho_info
->module
->format_info
[DFI_MACHO
]->u
.macho_info
->is_loader
= 0;
1503 TRACE("module = %p\n", macho_info
->module
);
1506 if (macho_info
->flags
& MACHO_INFO_NAME
)
1509 ptr
= HeapAlloc(GetProcessHeap(), 0, (lstrlenW(filename
) + 1) * sizeof(WCHAR
));
1512 lstrcpyW(ptr
, filename
);
1513 macho_info
->module_name
= ptr
;
1516 TRACE("module_name = %p %s\n", macho_info
->module_name
, debugstr_w(macho_info
->module_name
));
1519 macho_unmap_file(&fmap
);
1521 TRACE(" => %d\n", ret
);
1525 struct macho_load_params
1527 struct process
*process
;
1528 ULONG_PTR load_addr
;
1529 struct macho_info
*macho_info
;
1532 static BOOL
macho_load_file_cb(void *param
, HANDLE handle
, const WCHAR
*filename
)
1534 struct macho_load_params
*macho_load
= param
;
1535 return macho_load_file(macho_load
->process
, filename
, macho_load
->load_addr
, macho_load
->macho_info
);
1538 /******************************************************************
1539 * macho_search_and_load_file
1541 * Lookup a file in standard Mach-O locations, and if found, load it
1543 static BOOL
macho_search_and_load_file(struct process
* pcs
, const WCHAR
* filename
,
1544 ULONG_PTR load_addr
,
1545 struct macho_info
* macho_info
)
1548 struct module
* module
;
1550 struct macho_load_params load_params
;
1552 TRACE("(%p/%p, %s, 0x%08Ix, %p)\n", pcs
, pcs
->handle
, debugstr_w(filename
), load_addr
,
1555 if (filename
== NULL
|| *filename
== '\0') return FALSE
;
1556 if ((module
= module_is_already_loaded(pcs
, filename
)))
1558 macho_info
->module
= module
;
1559 module
->format_info
[DFI_MACHO
]->u
.macho_info
->in_use
= 1;
1560 return module
->module
.SymType
;
1563 if (wcsstr(filename
, L
"libstdc++")) return FALSE
; /* We know we can't do it */
1565 load_params
.process
= pcs
;
1566 load_params
.load_addr
= load_addr
;
1567 load_params
.macho_info
= macho_info
;
1569 /* Try DYLD_LIBRARY_PATH first. */
1570 p
= file_name(filename
);
1571 ret
= search_unix_path(p
, process_getenv(pcs
, L
"DYLD_LIBRARY_PATH"), macho_load_file_cb
, &load_params
);
1573 /* Try the path as given. */
1575 ret
= macho_load_file(pcs
, filename
, load_addr
, macho_info
);
1576 /* Try DYLD_FALLBACK_LIBRARY_PATH, with just the filename (no directories). */
1579 const WCHAR
* fallback
= process_getenv(pcs
, L
"DYLD_FALLBACK_LIBRARY_PATH");
1581 fallback
= L
"/usr/local/lib:/lib:/usr/lib";
1582 ret
= search_unix_path(p
, fallback
, macho_load_file_cb
, &load_params
);
1584 if (!ret
&& p
== filename
)
1585 ret
= search_dll_path(pcs
, filename
, macho_load_file_cb
, &load_params
);
1590 /******************************************************************
1591 * macho_enum_modules_internal
1593 * Enumerate Mach-O modules from a running process
1595 static BOOL
macho_enum_modules_internal(const struct process
* pcs
,
1596 const WCHAR
* main_name
,
1597 enum_modules_cb cb
, void* user
)
1599 union wine_all_image_infos image_infos
;
1600 union wine_image_info
* info_array
= NULL
;
1604 WCHAR bufstrW
[MAX_PATH
];
1607 TRACE("(%p/%p, %s, %p, %p)\n", pcs
, pcs
->handle
, debugstr_w(main_name
), cb
,
1611 len
= sizeof(image_infos
.infos64
);
1613 len
= sizeof(image_infos
.infos32
);
1614 if (!pcs
->dbg_hdr_addr
||
1615 !read_process_memory(pcs
, pcs
->dbg_hdr_addr
, &image_infos
, len
))
1619 struct dyld_all_image_infos32 temp
= image_infos
.infos32
;
1620 image_infos
.infos64
.infoArrayCount
= temp
.infoArrayCount
;
1621 image_infos
.infos64
.infoArray
= temp
.infoArray
;
1623 if (!image_infos
.infos64
.infoArray
)
1625 TRACE("Process has %u image infos at %I64x\n", image_infos
.infos64
.infoArrayCount
, image_infos
.infos64
.infoArray
);
1628 len
= sizeof(info_array
->info64
);
1630 len
= sizeof(info_array
->info32
);
1631 len
*= image_infos
.infos64
.infoArrayCount
;
1632 info_array
= HeapAlloc(GetProcessHeap(), 0, len
);
1634 !read_process_memory(pcs
, image_infos
.infos64
.infoArray
, info_array
, len
))
1636 TRACE("... read image infos\n");
1638 for (i
= 0; i
< image_infos
.infos64
.infoArrayCount
; i
++)
1640 struct dyld_image_info64 info
;
1642 info
= info_array
[i
].info64
;
1645 struct dyld_image_info32
*info32
= &info_array
->info32
+ i
;
1646 info
.imageLoadAddress
= info32
->imageLoadAddress
;
1647 info
.imageFilePath
= info32
->imageFilePath
;
1649 if (info
.imageFilePath
&&
1650 read_process_memory(pcs
, info
.imageFilePath
, bufstr
, sizeof(bufstr
)))
1652 bufstr
[sizeof(bufstr
) - 1] = '\0';
1653 TRACE("[%d] image file %s\n", i
, debugstr_a(bufstr
));
1654 MultiByteToWideChar(CP_UNIXCP
, 0, bufstr
, -1, bufstrW
, ARRAY_SIZE(bufstrW
));
1655 if (main_name
&& !bufstrW
[0]) lstrcpyW(bufstrW
, main_name
);
1656 if (!cb(bufstrW
, info
.imageLoadAddress
, user
)) break;
1662 HeapFree(GetProcessHeap(), 0, info_array
);
1668 struct process
* pcs
;
1669 struct macho_info macho_info
;
1672 static BOOL
macho_enum_sync_cb(const WCHAR
* name
, ULONG_PTR addr
, void* user
)
1674 struct macho_sync
* ms
= user
;
1676 TRACE("(%s, 0x%08Ix, %p)\n", debugstr_w(name
), addr
, user
);
1677 macho_search_and_load_file(ms
->pcs
, name
, addr
, &ms
->macho_info
);
1681 /******************************************************************
1682 * macho_synchronize_module_list
1684 * Rescans the debuggee's modules list and synchronizes it with
1685 * the one from 'pcs', ie:
1686 * - if a module is in debuggee and not in pcs, it's loaded into pcs
1687 * - if a module is in pcs and not in debuggee, it's unloaded from pcs
1689 static BOOL
macho_synchronize_module_list(struct process
* pcs
)
1691 struct module
* module
;
1692 struct macho_sync ms
;
1694 TRACE("(%p/%p)\n", pcs
, pcs
->handle
);
1696 for (module
= pcs
->lmodules
; module
; module
= module
->next
)
1698 if (module
->type
== DMT_MACHO
&& !module
->is_virtual
)
1699 module
->format_info
[DFI_MACHO
]->u
.macho_info
->in_use
= 0;
1703 ms
.macho_info
.flags
= MACHO_INFO_MODULE
;
1704 if (!macho_enum_modules_internal(pcs
, NULL
, macho_enum_sync_cb
, &ms
))
1707 module
= pcs
->lmodules
;
1710 if (module
->type
== DMT_MACHO
&& !module
->is_virtual
&&
1711 !module
->format_info
[DFI_MACHO
]->u
.macho_info
->in_use
&&
1712 !module
->format_info
[DFI_MACHO
]->u
.macho_info
->is_loader
)
1714 module_remove(pcs
, module
);
1715 /* restart all over */
1716 module
= pcs
->lmodules
;
1718 else module
= module
->next
;
1723 /******************************************************************
1724 * macho_enum_modules
1726 * Enumerates the Mach-O loaded modules from a running target (hProc)
1727 * This function doesn't require that someone has called SymInitialize
1728 * on this very process.
1730 static BOOL
macho_enum_modules(struct process
* process
, enum_modules_cb cb
, void* user
)
1732 struct macho_info macho_info
;
1735 TRACE("(%p, %p, %p)\n", process
->handle
, cb
, user
);
1736 macho_info
.flags
= MACHO_INFO_NAME
;
1737 macho_info
.module_name
= NULL
;
1738 ret
= macho_enum_modules_internal(process
, macho_info
.module_name
, cb
, user
);
1739 HeapFree(GetProcessHeap(), 0, (char*)macho_info
.module_name
);
1745 struct process
* pcs
;
1746 struct macho_info macho_info
;
1751 /******************************************************************
1754 * Callback for macho_load_module, used to walk the list of loaded
1757 static BOOL
macho_load_cb(const WCHAR
* name
, ULONG_PTR addr
, void* user
)
1759 struct macho_load
* ml
= user
;
1762 TRACE("(%s, 0x%08Ix, %p)\n", debugstr_w(name
), addr
, user
);
1764 /* memcmp is needed for matches when bufstr contains also version information
1765 * ml->name: libc.so, name: libc.so.6.0
1767 p
= file_name(name
);
1768 if (!memcmp(p
, ml
->name
, lstrlenW(ml
->name
) * sizeof(WCHAR
)))
1770 ml
->ret
= macho_search_and_load_file(ml
->pcs
, name
, addr
, &ml
->macho_info
);
1776 /******************************************************************
1779 * Loads a Mach-O module and stores it in process' module list.
1780 * Also, find module real name and load address from
1781 * the real loaded modules list in pcs address space.
1783 static struct module
* macho_load_module(struct process
* pcs
, const WCHAR
* name
, ULONG_PTR addr
)
1785 struct macho_load ml
;
1787 TRACE("(%p/%p, %s, 0x%08Ix)\n", pcs
, pcs
->handle
, debugstr_w(name
), addr
);
1789 ml
.macho_info
.flags
= MACHO_INFO_MODULE
;
1792 if (pcs
->dbg_hdr_addr
) /* we're debugging a live target */
1795 /* do only the lookup from the filename, not the path (as we lookup module
1796 * name in the process' loaded module list)
1798 ml
.name
= file_name(name
);
1801 if (!macho_enum_modules_internal(pcs
, NULL
, macho_load_cb
, &ml
))
1807 ml
.ret
= macho_search_and_load_file(pcs
, ml
.name
, addr
, &ml
.macho_info
);
1809 if (!ml
.ret
) return NULL
;
1810 assert(ml
.macho_info
.module
);
1811 return ml
.macho_info
.module
;
1814 /******************************************************************
1815 * macho_search_loader
1817 * Lookup in a running Mach-O process the loader, and sets its Mach-O link
1818 * address (for accessing the list of loaded images) in pcs.
1819 * If flags is MACHO_INFO_MODULE, the module for the loader is also
1820 * added as a module into pcs.
1822 static BOOL
macho_search_loader(struct process
* pcs
, struct macho_info
* macho_info
)
1825 union wine_all_image_infos image_infos
;
1826 union wine_image_info image_info
;
1829 BOOL got_path
= FALSE
;
1832 len
= sizeof(image_infos
.infos64
);
1834 len
= sizeof(image_infos
.infos32
);
1835 if (read_process_memory(pcs
, pcs
->dbg_hdr_addr
, &image_infos
, len
))
1838 len
= sizeof(image_info
.info64
);
1841 struct dyld_all_image_infos32 temp
= image_infos
.infos32
;
1842 image_infos
.infos64
.infoArrayCount
= temp
.infoArrayCount
;
1843 image_infos
.infos64
.infoArray
= temp
.infoArray
;
1844 len
= sizeof(image_info
.info32
);
1846 if (image_infos
.infos64
.infoArray
&& image_infos
.infos64
.infoArrayCount
&&
1847 read_process_memory(pcs
, image_infos
.infos64
.infoArray
, &image_info
, len
))
1851 struct dyld_image_info32 temp
= image_info
.info32
;
1852 image_info
.info64
.imageLoadAddress
= temp
.imageLoadAddress
;
1853 image_info
.info64
.imageFilePath
= temp
.imageFilePath
;
1855 for (len
= sizeof(path
); image_info
.info64
.imageFilePath
&& len
> 0; len
/= 2)
1857 if (read_process_memory(pcs
, image_info
.info64
.imageFilePath
, path
, len
))
1861 TRACE("got executable path from target's dyld image info: %s\n", debugstr_a(path
));
1872 len
= MultiByteToWideChar(CP_UNIXCP
, 0, path
, -1, NULL
, 0);
1873 pathW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1876 MultiByteToWideChar(CP_UNIXCP
, 0, path
, -1, pathW
, len
);
1877 ret
= macho_load_file(pcs
, pathW
, 0, macho_info
);
1878 HeapFree(GetProcessHeap(), 0, pathW
);
1884 WCHAR
* loader
= get_wine_loader_name(pcs
);
1887 ret
= macho_search_and_load_file(pcs
, loader
, 0, macho_info
);
1888 HeapFree(GetProcessHeap(), 0, loader
);
1894 static const struct loader_ops macho_loader_ops
=
1896 macho_synchronize_module_list
,
1898 macho_load_debug_info
,
1900 macho_fetch_file_info
,
1903 /******************************************************************
1904 * macho_read_wine_loader_dbg_info
1906 * Try to find a decent wine executable which could have loaded the debuggee
1908 BOOL
macho_read_wine_loader_dbg_info(struct process
* pcs
, ULONG_PTR addr
)
1910 struct macho_info macho_info
;
1912 TRACE("(%p/%p)\n", pcs
, pcs
->handle
);
1913 pcs
->dbg_hdr_addr
= addr
;
1914 macho_info
.flags
= MACHO_INFO_MODULE
;
1915 if (!macho_search_loader(pcs
, &macho_info
)) return FALSE
;
1916 macho_info
.module
->format_info
[DFI_MACHO
]->u
.macho_info
->is_loader
= 1;
1917 module_set_module(macho_info
.module
, S_WineLoaderW
);
1918 pcs
->loader
= &macho_loader_ops
;
1919 TRACE("Found macho debug header %#Ix\n", pcs
->dbg_hdr_addr
);