2 * File macho_module.c - processing of Mach-O files
3 * Originally based on elf_module.c
5 * Copyright (C) 1996, Eric Youngdale.
6 * 1999-2007 Eric Pouech
7 * 2009 Ken Thomases, CodeWeavers Inc.
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24 #include "dbghelp_private.h"
26 #ifdef HAVE_MACH_O_LOADER_H
28 #include <mach-o/fat.h>
29 #include <mach-o/loader.h>
30 #include <mach-o/nlist.h>
32 #ifdef HAVE_MACH_O_DYLD_IMAGES_H
33 #include <mach-o/dyld_images.h>
35 struct dyld_image_info
{
36 const struct mach_header
*imageLoadAddress
;
37 const char *imageFilePath
;
38 uintptr_t imageFileModDate
;
41 struct dyld_all_image_infos
{
43 uint32_t infoArrayCount
;
44 const struct dyld_image_info
*infoArray
;
46 int processDetachedFromSharedRegion
;
51 #include "wine/library.h"
52 #include "wine/debug.h"
54 #ifdef WORDS_BIGENDIAN
55 #define swap_ulong_be_to_host(n) (n)
57 #define swap_ulong_be_to_host(n) (RtlUlongByteSwap(n))
60 WINE_DEFAULT_DEBUG_CHANNEL(dbghelp_macho
);
63 struct macho_module_info
65 unsigned long load_addr
;
66 unsigned short in_use
: 1,
70 #define MACHO_INFO_DEBUG_HEADER 0x0001
71 #define MACHO_INFO_MODULE 0x0002
72 #define MACHO_INFO_NAME 0x0004
76 unsigned flags
; /* IN one (or several) of the MACHO_INFO constants */
77 unsigned long dbg_hdr_addr
; /* OUT address of debug header (if MACHO_INFO_DEBUG_HEADER is set) */
78 struct module
* module
; /* OUT loaded module (if MACHO_INFO_MODULE is set) */
79 const WCHAR
* module_name
; /* OUT found module name (if MACHO_INFO_NAME is set) */
82 /* structure holding information while handling a Mach-O image */
83 #define BITS_PER_ULONG (sizeof(ULONG) * 8)
84 #define ULONGS_FOR_BITS(nbits) (((nbits) + BITS_PER_ULONG - 1) / BITS_PER_ULONG)
87 /* A copy of the Mach-O header for an individual architecture. */
88 struct mach_header mach_header
;
90 /* The mapped load commands. */
91 const struct load_command
* load_commands
;
93 /* The portion of the file which is this architecture. mach_header was
94 * read from arch_offset. */
98 /* The range of address space covered by all segments. */
102 /* Map of which sections contain code. Sections are accessed using 1-based
103 * index. Bit 0 of this bitset indicates if the bitset has been initialized. */
104 RTL_BITMAP sect_is_code
;
105 ULONG sect_is_code_buff
[ULONGS_FOR_BITS(MAX_SECT
+ 1)];
111 static void macho_unmap_file(struct macho_file_map
* fmap
);
113 /******************************************************************
116 * For a range (offset & length) of a single architecture within
117 * a Mach-O file, calculate the page-aligned range of the whole file
118 * that encompasses it. For a fat binary, the architecture will
119 * itself be offset within the file, so take that into account.
121 static void macho_calc_range(const struct macho_file_map
* fmap
, unsigned offset
,
122 unsigned len
, unsigned* out_aligned_offset
,
123 unsigned* out_aligned_end
, unsigned* out_aligned_len
,
124 unsigned* out_misalign
)
126 unsigned pagemask
= sysconf( _SC_PAGESIZE
) - 1;
127 unsigned file_offset
, misalign
;
129 file_offset
= fmap
->arch_offset
+ offset
;
130 misalign
= file_offset
& pagemask
;
131 *out_aligned_offset
= file_offset
- misalign
;
132 *out_aligned_end
= (file_offset
+ len
+ pagemask
) & ~pagemask
;
134 *out_aligned_len
= *out_aligned_end
- *out_aligned_offset
;
136 *out_misalign
= misalign
;
139 /******************************************************************
142 * Maps a range (offset, length in bytes) from a Mach-O file into memory
144 static const char* macho_map_range(const struct macho_file_map
* fmap
, unsigned offset
, unsigned len
)
146 unsigned misalign
, aligned_offset
, aligned_map_end
, map_size
;
147 const void* aligned_ptr
;
149 TRACE("(%p/%d, 0x%08x, 0x%08x)\n", fmap
, fmap
->fd
, offset
, len
);
151 macho_calc_range(fmap
, offset
, len
, &aligned_offset
, &aligned_map_end
,
152 &map_size
, &misalign
);
154 aligned_ptr
= mmap(NULL
, map_size
, PROT_READ
, MAP_PRIVATE
, fmap
->fd
, aligned_offset
);
156 TRACE("Mapped (0x%08x - 0x%08x) to %p\n", aligned_offset
, aligned_map_end
, aligned_ptr
);
158 if (aligned_ptr
== MAP_FAILED
) return MACHO_NO_MAP
;
159 return (const char*)aligned_ptr
+ misalign
;
162 /******************************************************************
165 * Unmaps a range (offset, length in bytes) of a Mach-O file from memory
167 static void macho_unmap_range(const void** mapped
, const struct macho_file_map
* fmap
,
168 unsigned offset
, unsigned len
)
170 TRACE("(%p, %p/%d, 0x%08x, 0x%08x)\n", mapped
, fmap
, fmap
->fd
, offset
, len
);
172 if (mapped
&& *mapped
!= MACHO_NO_MAP
)
174 unsigned misalign
, aligned_offset
, aligned_map_end
, map_size
;
177 macho_calc_range(fmap
, offset
, len
, &aligned_offset
, &aligned_map_end
,
178 &map_size
, &misalign
);
180 aligned_ptr
= (char*)*mapped
- misalign
;
181 if (munmap(aligned_ptr
, map_size
) < 0)
182 WARN("Couldn't unmap the range\n");
183 TRACE("Unmapped (0x%08x - 0x%08x) from %p - %p\n", aligned_offset
, aligned_map_end
, aligned_ptr
, (char*)aligned_ptr
+ map_size
);
184 *mapped
= MACHO_NO_MAP
;
188 /******************************************************************
191 * Maps two ranges (offset, length in bytes) from a Mach-O file
192 * into memory. If the two ranges overlap, use one mmap so that
193 * the munmap doesn't fragment the mapping.
195 static BOOL
macho_map_ranges(const struct macho_file_map
* fmap
,
196 unsigned offset1
, unsigned len1
,
197 unsigned offset2
, unsigned len2
,
198 const void** mapped1
, const void** mapped2
)
200 unsigned aligned_offset1
, aligned_map_end1
;
201 unsigned aligned_offset2
, aligned_map_end2
;
203 TRACE("(%p/%d, 0x%08x, 0x%08x, 0x%08x, 0x%08x, %p, %p)\n", fmap
, fmap
->fd
,
204 offset1
, len1
, offset2
, len2
, mapped1
, mapped2
);
206 macho_calc_range(fmap
, offset1
, len1
, &aligned_offset1
, &aligned_map_end1
, NULL
, NULL
);
207 macho_calc_range(fmap
, offset2
, len2
, &aligned_offset2
, &aligned_map_end2
, NULL
, NULL
);
209 if (aligned_map_end1
< aligned_offset2
|| aligned_map_end2
< aligned_offset1
)
211 *mapped1
= macho_map_range(fmap
, offset1
, len1
);
212 if (*mapped1
!= MACHO_NO_MAP
)
214 *mapped2
= macho_map_range(fmap
, offset2
, len2
);
215 if (*mapped2
== MACHO_NO_MAP
)
216 macho_unmap_range(mapped1
, fmap
, offset1
, len1
);
221 if (offset1
< offset2
)
223 *mapped1
= macho_map_range(fmap
, offset1
, offset2
+ len2
- offset1
);
224 if (*mapped1
!= MACHO_NO_MAP
)
225 *mapped2
= (const char*)*mapped1
+ offset2
- offset1
;
229 *mapped2
= macho_map_range(fmap
, offset2
, offset1
+ len1
- offset2
);
230 if (*mapped2
!= MACHO_NO_MAP
)
231 *mapped1
= (const char*)*mapped2
+ offset1
- offset2
;
235 TRACE(" => %p, %p\n", *mapped1
, *mapped2
);
237 return (*mapped1
!= MACHO_NO_MAP
) && (*mapped2
!= MACHO_NO_MAP
);
240 /******************************************************************
243 * Unmaps two ranges (offset, length in bytes) of a Mach-O file
244 * from memory. Use for ranges which were mapped by
247 static void macho_unmap_ranges(const struct macho_file_map
* fmap
,
248 unsigned offset1
, unsigned len1
,
249 unsigned offset2
, unsigned len2
,
250 const void** mapped1
, const void** mapped2
)
252 unsigned aligned_offset1
, aligned_map_end1
;
253 unsigned aligned_offset2
, aligned_map_end2
;
255 TRACE("(%p/%d, 0x%08x, 0x%08x, 0x%08x, 0x%08x, %p/%p, %p/%p)\n", fmap
, fmap
->fd
,
256 offset1
, len1
, offset2
, len2
, mapped1
, *mapped1
, mapped2
, *mapped2
);
258 macho_calc_range(fmap
, offset1
, len1
, &aligned_offset1
, &aligned_map_end1
, NULL
, NULL
);
259 macho_calc_range(fmap
, offset2
, len2
, &aligned_offset2
, &aligned_map_end2
, NULL
, NULL
);
261 if (aligned_map_end1
< aligned_offset2
|| aligned_map_end2
< aligned_offset1
)
263 macho_unmap_range(mapped1
, fmap
, offset1
, len1
);
264 macho_unmap_range(mapped2
, fmap
, offset2
, len2
);
268 if (offset1
< offset2
)
270 macho_unmap_range(mapped1
, fmap
, offset1
, offset2
+ len2
- offset1
);
271 *mapped2
= MACHO_NO_MAP
;
275 macho_unmap_range(mapped2
, fmap
, offset2
, offset1
+ len1
- offset2
);
276 *mapped1
= MACHO_NO_MAP
;
281 /******************************************************************
282 * macho_map_load_commands
284 * Maps the load commands from a Mach-O file into memory
286 static const struct load_command
* macho_map_load_commands(struct macho_file_map
* fmap
)
288 if (fmap
->load_commands
== MACHO_NO_MAP
)
290 fmap
->load_commands
= (const struct load_command
*) macho_map_range(
291 fmap
, sizeof(fmap
->mach_header
), fmap
->mach_header
.sizeofcmds
);
292 TRACE("Mapped load commands: %p\n", fmap
->load_commands
);
295 return fmap
->load_commands
;
298 /******************************************************************
299 * macho_unmap_load_commands
301 * Unmaps the load commands of a Mach-O file from memory
303 static void macho_unmap_load_commands(struct macho_file_map
* fmap
)
305 if (fmap
->load_commands
!= MACHO_NO_MAP
)
307 TRACE("Unmapping load commands: %p\n", fmap
->load_commands
);
308 macho_unmap_range((const void**)&fmap
->load_commands
, fmap
,
309 sizeof(fmap
->mach_header
), fmap
->mach_header
.sizeofcmds
);
313 /******************************************************************
314 * macho_next_load_command
316 * Advance to the next load command
318 static const struct load_command
* macho_next_load_command(const struct load_command
* lc
)
320 return (const struct load_command
*)((const char*)lc
+ lc
->cmdsize
);
323 /******************************************************************
324 * macho_enum_load_commands
326 * Enumerates the load commands for a Mach-O file, selecting by
327 * the command type, calling a callback for each. If the callback
328 * returns <0, that indicates an error. If it returns >0, that means
329 * it's not interested in getting any more load commands.
330 * If this function returns <0, that's an error produced by the
331 * callback. If >=0, that's the count of load commands successfully
334 static int macho_enum_load_commands(struct macho_file_map
* fmap
, unsigned cmd
,
335 int (*cb
)(struct macho_file_map
*, const struct load_command
*, void*),
338 const struct load_command
* lc
;
342 TRACE("(%p/%d, %u, %p, %p)\n", fmap
, fmap
->fd
, cmd
, cb
, user
);
344 if ((lc
= macho_map_load_commands(fmap
)) == MACHO_NO_MAP
) return -1;
346 TRACE("%d total commands\n", fmap
->mach_header
.ncmds
);
348 for (i
= 0; i
< fmap
->mach_header
.ncmds
; i
++, lc
= macho_next_load_command(lc
))
352 if (cmd
&& cmd
!= lc
->cmd
) continue;
355 result
= cb(fmap
, lc
, user
);
356 TRACE("load_command[%d] (%p), cmd %u; callback => %d\n", i
, lc
, lc
->cmd
, result
);
357 if (result
) return (result
< 0) ? result
: count
;
363 /******************************************************************
364 * macho_accum_segs_range
366 * Callback for macho_enum_load_commands. Accumulates the address
367 * range covered by the segments of a Mach-O file. All commands
368 * are expected to be of LC_SEGMENT type.
370 static int macho_accum_segs_range(struct macho_file_map
* fmap
,
371 const struct load_command
* lc
, void* user
)
373 const struct segment_command
* sc
= (const struct segment_command
*)lc
;
374 unsigned tmp
, page_mask
= sysconf( _SC_PAGESIZE
) - 1;
376 TRACE("(%p/%d, %p, %p) before: 0x%08x - 0x%08x\n", fmap
, fmap
->fd
, lc
, user
,
377 (unsigned)fmap
->segs_start
, (unsigned)fmap
->segs_size
);
378 TRACE("Segment command vm: 0x%08x - 0x%08x\n", (unsigned)sc
->vmaddr
,
379 (unsigned)sc
->vmaddr
+ sc
->vmsize
);
381 if (!strncmp(sc
->segname
, "WINE_", 5))
383 TRACE("Ignoring special Wine segment %s\n", debugstr_an(sc
->segname
, sizeof(sc
->segname
)));
387 /* If this segment starts before previously-known earliest, record
389 if (sc
->vmaddr
< fmap
->segs_start
)
390 fmap
->segs_start
= sc
->vmaddr
;
392 /* If this segment extends beyond previously-known furthest, record
394 tmp
= (sc
->vmaddr
+ sc
->vmsize
+ page_mask
) & ~page_mask
;
395 if (fmap
->segs_size
< tmp
) fmap
->segs_size
= tmp
;
397 TRACE("after: 0x%08x - 0x%08x\n", (unsigned)fmap
->segs_start
, (unsigned)fmap
->segs_size
);
402 /******************************************************************
405 * Maps a Mach-O file into memory (and checks it's a real Mach-O file)
407 static BOOL
macho_map_file(const WCHAR
* filenameW
, struct macho_file_map
* fmap
)
409 struct fat_header fat_header
;
416 TRACE("(%s, %p)\n", debugstr_w(filenameW
), fmap
);
419 fmap
->load_commands
= MACHO_NO_MAP
;
420 RtlInitializeBitMap(&fmap
->sect_is_code
, fmap
->sect_is_code_buff
, MAX_SECT
+ 1);
422 len
= WideCharToMultiByte(CP_UNIXCP
, 0, filenameW
, -1, NULL
, 0, NULL
, NULL
);
423 if (!(filename
= HeapAlloc(GetProcessHeap(), 0, len
)))
425 WARN("failed to allocate filename buffer\n");
428 WideCharToMultiByte(CP_UNIXCP
, 0, filenameW
, -1, filename
, len
, NULL
, NULL
);
430 /* check that the file exists */
431 if (stat(filename
, &statbuf
) == -1 || S_ISDIR(statbuf
.st_mode
))
433 TRACE("stat() failed or %s is directory: %s\n", debugstr_a(filename
), strerror(errno
));
437 /* Now open the file, so that we can mmap() it. */
438 if ((fmap
->fd
= open(filename
, O_RDONLY
)) == -1)
440 TRACE("failed to open file %s: %d\n", debugstr_a(filename
), errno
);
444 if (read(fmap
->fd
, &fat_header
, sizeof(fat_header
)) != sizeof(fat_header
))
446 TRACE("failed to read fat header: %d\n", errno
);
449 TRACE("... got possible fat header\n");
451 /* Fat header is always in big-endian order. */
452 if (swap_ulong_be_to_host(fat_header
.magic
) == FAT_MAGIC
)
454 int narch
= swap_ulong_be_to_host(fat_header
.nfat_arch
);
455 for (i
= 0; i
< narch
; i
++)
457 struct fat_arch fat_arch
;
458 if (read(fmap
->fd
, &fat_arch
, sizeof(fat_arch
)) != sizeof(fat_arch
))
460 if (swap_ulong_be_to_host(fat_arch
.cputype
) == CPU_TYPE_X86
)
462 fmap
->arch_offset
= swap_ulong_be_to_host(fat_arch
.offset
);
463 fmap
->arch_size
= swap_ulong_be_to_host(fat_arch
.size
);
467 if (i
>= narch
) goto done
;
468 TRACE("... found x86 arch\n");
472 fmap
->arch_offset
= 0;
473 fmap
->arch_size
= statbuf
.st_size
;
474 TRACE("... not a fat header\n");
477 /* Individual architecture (standalone or within a fat file) is in its native byte order. */
478 lseek(fmap
->fd
, fmap
->arch_offset
, SEEK_SET
);
479 if (read(fmap
->fd
, &fmap
->mach_header
, sizeof(fmap
->mach_header
)) != sizeof(fmap
->mach_header
))
481 TRACE("... got possible Mach header\n");
482 /* and check for a Mach-O header */
483 if (fmap
->mach_header
.magic
!= MH_MAGIC
||
484 fmap
->mach_header
.cputype
!= CPU_TYPE_X86
) goto done
;
485 /* Make sure the file type is one of the ones we expect. */
486 switch (fmap
->mach_header
.filetype
)
496 TRACE("... verified Mach x86 header\n");
499 fmap
->segs_start
= ~0L;
501 if (macho_enum_load_commands(fmap
, LC_SEGMENT
, macho_accum_segs_range
, NULL
) < 0)
504 fmap
->segs_size
-= fmap
->segs_start
;
505 TRACE("segs_start: 0x%08x, segs_size: 0x%08x\n", (unsigned)fmap
->segs_start
,
506 (unsigned)fmap
->segs_size
);
511 macho_unmap_file(fmap
);
512 HeapFree(GetProcessHeap(), 0, filename
);
516 /******************************************************************
519 * Unmaps a Mach-O file from memory (previously mapped with macho_map_file)
521 static void macho_unmap_file(struct macho_file_map
* fmap
)
523 TRACE("(%p/%d)\n", fmap
, fmap
->fd
);
526 macho_unmap_load_commands(fmap
);
532 /******************************************************************
533 * macho_fill_sect_is_code
535 * Callback for macho_enum_load_commands. Determines which segments
536 * of a Mach-O file contain code. All commands are expected to be
537 * of LC_SEGMENT type.
539 static int macho_fill_sect_is_code(struct macho_file_map
* fmap
,
540 const struct load_command
* lc
, void* user
)
542 const struct segment_command
* sc
= (const struct segment_command
*)lc
;
543 const struct section
* sections
;
547 TRACE("(%p/%d, %p, %p/%d) scanning %u sections\n", fmap
, fmap
->fd
, lc
,
548 cursect
, *cursect
, sc
->nsects
);
550 sections
= (const struct section
*)(sc
+ 1);
551 for (i
= 0; i
< sc
->nsects
; i
++)
553 if (*cursect
> MAX_SECT
) return -1;
556 if (!(sections
[i
].flags
& SECTION_TYPE
) &&
557 (sections
[i
].flags
& (S_ATTR_PURE_INSTRUCTIONS
|S_ATTR_SOME_INSTRUCTIONS
)))
558 RtlSetBits(&fmap
->sect_is_code
, *cursect
, 1);
560 RtlClearBits(&fmap
->sect_is_code
, *cursect
, 1);
561 TRACE("Section %d (%d of this segment) is%s code\n", *cursect
, i
,
562 (RtlAreBitsSet(&fmap
->sect_is_code
, *cursect
, 1) ? "" : " not"));
568 /******************************************************************
571 * Checks if a section, identified by sectidx which is a 1-based
572 * index into the sections of all segments, in order of load
573 * commands, contains code.
575 static BOOL
macho_sect_is_code(struct macho_file_map
* fmap
, unsigned char sectidx
)
577 TRACE("(%p/%d, %u)\n", fmap
, fmap
->fd
, sectidx
);
579 if (!RtlAreBitsSet(&fmap
->sect_is_code
, 0, 1))
582 if (macho_enum_load_commands(fmap
, LC_SEGMENT
, macho_fill_sect_is_code
, &cursect
) < 0)
583 WARN("Couldn't load sect_is_code map\n");
584 RtlSetBits(&fmap
->sect_is_code
, 0, 1);
587 return RtlAreBitsSet(&fmap
->sect_is_code
, sectidx
, 1);
592 struct hash_table_elt ht_elt
;
593 struct symt_compiland
* compiland
;
595 unsigned char is_code
:1,
601 struct macho_debug_info
603 struct macho_file_map
* fmap
;
604 struct module
* module
;
606 struct hash_table ht_symtab
;
609 /******************************************************************
612 * Callback for stabs_parse. Collect symbol definitions.
614 static void macho_stabs_def_cb(struct module
* module
, unsigned long load_offset
,
615 const char* name
, unsigned long offset
,
616 BOOL is_public
, BOOL is_global
, unsigned char sectidx
,
617 struct symt_compiland
* compiland
, void* user
)
619 struct macho_debug_info
* mdi
= user
;
620 struct symtab_elt
* ste
;
622 TRACE("(%p, 0x%08lx, %s, 0x%08lx, %d, %d, %u, %p, %p/%p/%d)\n", module
, load_offset
,
623 debugstr_a(name
), offset
, is_public
, is_global
, sectidx
,
624 compiland
, mdi
, mdi
->fmap
, mdi
->fmap
->fd
);
626 /* Defer the creation of new non-debugging symbols until after we've
627 * finished parsing the stabs. */
628 ste
= pool_alloc(&mdi
->pool
, sizeof(*ste
));
629 ste
->ht_elt
.name
= pool_strdup(&mdi
->pool
, name
);
630 ste
->compiland
= compiland
;
631 ste
->addr
= load_offset
+ offset
;
632 ste
->is_code
= !!macho_sect_is_code(mdi
->fmap
, sectidx
);
633 ste
->is_public
= !!is_public
;
634 ste
->is_global
= !!is_global
;
636 hash_table_add(&mdi
->ht_symtab
, &ste
->ht_elt
);
639 /******************************************************************
642 * Callback for macho_enum_load_commands. Processes the LC_SYMTAB
643 * load commands from the Mach-O file.
645 static int macho_parse_symtab(struct macho_file_map
* fmap
,
646 const struct load_command
* lc
, void* user
)
648 const struct symtab_command
* sc
= (const struct symtab_command
*)lc
;
649 struct macho_debug_info
* mdi
= user
;
650 const struct nlist
* stab
;
654 TRACE("(%p/%d, %p, %p) %u syms at 0x%08x, strings 0x%08x - 0x%08x\n", fmap
, fmap
->fd
, lc
,
655 user
, sc
->nsyms
, sc
->symoff
, sc
->stroff
, sc
->stroff
+ sc
->strsize
);
657 if (!macho_map_ranges(fmap
, sc
->symoff
, sc
->nsyms
* sizeof(struct nlist
),
658 sc
->stroff
, sc
->strsize
, (const void**)&stab
, (const void**)&stabstr
))
661 if (!stabs_parse(mdi
->module
,
662 mdi
->module
->format_info
[DFI_MACHO
]->u
.macho_info
->load_addr
- fmap
->segs_start
,
663 stab
, sc
->nsyms
* sizeof(struct nlist
),
664 stabstr
, sc
->strsize
, macho_stabs_def_cb
, mdi
))
667 macho_unmap_ranges(fmap
, sc
->symoff
, sc
->nsyms
* sizeof(struct nlist
),
668 sc
->stroff
, sc
->strsize
, (const void**)&stab
, (const void**)&stabstr
);
673 /******************************************************************
676 * Integrate the non-debugging symbols we've gathered into the
677 * symbols that were generated during stabs parsing.
679 static void macho_finish_stabs(struct module
* module
, struct hash_table
* ht_symtab
)
681 struct hash_table_iter hti_ours
;
682 struct symtab_elt
* ste
;
683 BOOL adjusted
= FALSE
;
685 TRACE("(%p, %p)\n", module
, ht_symtab
);
687 /* For each of our non-debugging symbols, see if it can provide some
688 * missing details to one of the module's known symbols. */
689 hash_table_iter_init(ht_symtab
, &hti_ours
, NULL
);
690 while ((ste
= hash_table_iter_up(&hti_ours
)))
692 struct hash_table_iter hti_modules
;
695 struct symt_function
* func
;
696 struct symt_data
* data
;
698 hash_table_iter_init(&module
->ht_symbols
, &hti_modules
, ste
->ht_elt
.name
);
699 while ((ptr
= hash_table_iter_up(&hti_modules
)))
701 sym
= GET_ENTRY(ptr
, struct symt_ht
, hash_elt
);
703 if (strcmp(sym
->hash_elt
.name
, ste
->ht_elt
.name
))
706 switch (sym
->symt
.tag
)
709 func
= (struct symt_function
*)sym
;
710 if (func
->address
== module
->format_info
[DFI_MACHO
]->u
.macho_info
->load_addr
)
712 TRACE("Adjusting function %p/%s!%s from 0x%08lx to 0x%08lx\n", func
,
713 debugstr_w(module
->module
.ModuleName
), sym
->hash_elt
.name
,
714 func
->address
, ste
->addr
);
715 func
->address
= ste
->addr
;
718 if (func
->address
== ste
->addr
)
722 data
= (struct symt_data
*)sym
;
726 case DataIsFileStatic
:
727 if (data
->u
.var
.offset
== module
->format_info
[DFI_MACHO
]->u
.macho_info
->load_addr
)
729 TRACE("Adjusting data symbol %p/%s!%s from 0x%08lx to 0x%08lx\n",
730 data
, debugstr_w(module
->module
.ModuleName
), sym
->hash_elt
.name
,
731 data
->u
.var
.offset
, ste
->addr
);
732 data
->u
.var
.offset
= ste
->addr
;
735 if (data
->u
.var
.offset
== ste
->addr
)
737 enum DataKind new_kind
;
739 new_kind
= ste
->is_global
? DataIsGlobal
: DataIsFileStatic
;
740 if (data
->kind
!= new_kind
)
742 WARN("Changing kind for %p/%s!%s from %d to %d\n", sym
,
743 debugstr_w(module
->module
.ModuleName
), sym
->hash_elt
.name
,
744 (int)data
->kind
, (int)new_kind
);
745 data
->kind
= new_kind
;
755 TRACE("Ignoring tag %u\n", sym
->symt
.tag
);
763 /* since we may have changed some addresses, mark the module to be resorted */
764 module
->sortlist_valid
= FALSE
;
767 /* Mark any of our non-debugging symbols which fall on an already-used
768 * address as "used". This allows us to skip them in the next loop,
769 * below. We do this in separate loops because symt_new_* marks the
770 * list as needing sorting and symt_find_nearest sorts if needed,
771 * causing thrashing. */
772 if (!(dbghelp_options
& SYMOPT_PUBLICS_ONLY
))
774 hash_table_iter_init(ht_symtab
, &hti_ours
, NULL
);
775 while ((ste
= hash_table_iter_up(&hti_ours
)))
780 if (ste
->used
) continue;
782 sym
= symt_find_nearest(module
, ste
->addr
);
784 symt_get_address(&sym
->symt
, &addr
);
785 if (sym
&& ste
->addr
== addr
)
792 /* If neither symbol has a correct size (ours never does), we
793 * consider them both to be markers. No warning is needed in
795 * Also, we check that we don't have two symbols, one local, the other
796 * global, which is legal.
798 symt_get_info(module
, &sym
->symt
, TI_GET_LENGTH
, &size
);
799 symt_get_info(module
, &sym
->symt
, TI_GET_DATAKIND
, &kind
);
800 if (size
&& kind
== (ste
->is_global
? DataIsGlobal
: DataIsFileStatic
))
801 FIXME("Duplicate in %s: %s<%08lx> %s<%s-%s>\n",
802 debugstr_w(module
->module
.ModuleName
),
803 ste
->ht_elt
.name
, ste
->addr
,
805 wine_dbgstr_longlong(addr
), wine_dbgstr_longlong(size
));
810 /* For any of our remaining non-debugging symbols which have no match
811 * among the module's known symbols, add them as new symbols. */
812 hash_table_iter_init(ht_symtab
, &hti_ours
, NULL
);
813 while ((ste
= hash_table_iter_up(&hti_ours
)))
815 if (!(dbghelp_options
& SYMOPT_PUBLICS_ONLY
) && !ste
->used
)
819 symt_new_function(module
, ste
->compiland
, ste
->ht_elt
.name
,
826 loc
.kind
= loc_absolute
;
828 loc
.offset
= ste
->addr
;
829 symt_new_global_variable(module
, ste
->compiland
, ste
->ht_elt
.name
,
830 !ste
->is_global
, loc
, 0, NULL
);
836 if (ste
->is_public
&& !(dbghelp_options
& SYMOPT_NO_PUBLICS
))
838 symt_new_public(module
, ste
->compiland
, ste
->ht_elt
.name
, ste
->addr
, 0);
843 /******************************************************************
844 * macho_load_debug_info_from_map
846 * Loads the symbolic information from a Mach-O module.
848 * FALSE if the file doesn't contain symbolic info (or this info
849 * cannot be read or parsed)
852 static BOOL
macho_load_debug_info_from_map(struct module
* module
,
853 struct macho_file_map
* fmap
)
856 struct macho_debug_info mdi
;
859 TRACE("(%p, %p/%d)\n", module
, fmap
, fmap
->fd
);
861 module
->module
.SymType
= SymExport
;
865 pool_init(&mdi
.pool
, 65536);
866 hash_table_init(&mdi
.pool
, &mdi
.ht_symtab
, 256);
867 result
= macho_enum_load_commands(fmap
, LC_SYMTAB
, macho_parse_symtab
, &mdi
);
871 WARN("Couldn't correctly read stabs\n");
873 macho_finish_stabs(module
, &mdi
.ht_symtab
);
875 pool_destroy(&mdi
.pool
);
879 /******************************************************************
880 * macho_load_debug_info
882 * Loads Mach-O debugging information from the module image file.
884 BOOL
macho_load_debug_info(struct module
* module
, struct macho_file_map
* fmap
)
887 struct macho_file_map my_fmap
;
889 TRACE("(%p, %p/%d)\n", module
, fmap
, fmap
? fmap
->fd
: -1);
891 if (module
->type
!= DMT_MACHO
|| !module
->format_info
[DFI_MACHO
]->u
.macho_info
)
893 ERR("Bad Mach-O module '%s'\n", debugstr_w(module
->module
.LoadedImageName
));
900 ret
= macho_map_file(module
->module
.LoadedImageName
, fmap
);
903 ret
= macho_load_debug_info_from_map(module
, fmap
);
905 if (fmap
== &my_fmap
) macho_unmap_file(fmap
);
909 /******************************************************************
910 * macho_fetch_file_info
912 * Gathers some more information for a Mach-O module from a given file
914 BOOL
macho_fetch_file_info(const WCHAR
* name
, DWORD_PTR
* base
,
915 DWORD
* size
, DWORD
* checksum
)
917 struct macho_file_map fmap
;
919 TRACE("(%s, %p, %p, %p)\n", debugstr_w(name
), base
, size
, checksum
);
921 if (!macho_map_file(name
, &fmap
)) return FALSE
;
922 if (base
) *base
= fmap
.segs_start
;
923 *size
= fmap
.segs_size
;
924 *checksum
= calc_crc32(fmap
.fd
);
925 macho_unmap_file(&fmap
);
929 /******************************************************************
932 * Loads the information for Mach-O module stored in 'filename'.
933 * The module has been loaded at 'load_addr' address.
935 * FALSE if the file cannot be found/opened or if the file doesn't
936 * contain symbolic info (or this info cannot be read or parsed)
939 static BOOL
macho_load_file(struct process
* pcs
, const WCHAR
* filename
,
940 unsigned long load_addr
, struct macho_info
* macho_info
)
943 struct macho_file_map fmap
;
945 TRACE("(%p/%p, %s, 0x%08lx, %p/0x%08x)\n", pcs
, pcs
->handle
, debugstr_w(filename
),
946 load_addr
, macho_info
, macho_info
->flags
);
948 if (!macho_map_file(filename
, &fmap
)) return FALSE
;
950 /* Find the dynamic loader's table of images loaded into the process.
952 if (macho_info
->flags
& MACHO_INFO_DEBUG_HEADER
)
954 PROCESS_BASIC_INFORMATION pbi
;
959 /* Get address of PEB */
960 status
= NtQueryInformationProcess(pcs
->handle
, ProcessBasicInformation
,
961 &pbi
, sizeof(pbi
), NULL
);
962 if (status
== STATUS_SUCCESS
)
964 ULONG dyld_image_info
;
966 /* Read dyld image info address from PEB */
967 if (ReadProcessMemory(pcs
->handle
, &pbi
.PebBaseAddress
->Reserved
,
968 &dyld_image_info
, sizeof(dyld_image_info
), NULL
))
970 TRACE("got dyld_image_info 0x%08x from PEB %p MacDyldImageInfo %p\n",
971 dyld_image_info
, pbi
.PebBaseAddress
, &pbi
.PebBaseAddress
->Reserved
);
972 macho_info
->dbg_hdr_addr
= dyld_image_info
;
979 static void* dyld_all_image_infos_addr
;
981 /* Our next best guess is that dyld was loaded at its base address
982 and we can find the dyld image infos address by looking up its symbol. */
983 if (!dyld_all_image_infos_addr
)
986 memset(nl
, 0, sizeof(nl
));
987 nl
[0].n_un
.n_name
= (char*)"_dyld_all_image_infos";
988 if (!nlist("/usr/lib/dyld", nl
))
989 dyld_all_image_infos_addr
= (void*)nl
[0].n_value
;
992 if (dyld_all_image_infos_addr
)
994 TRACE("got dyld_image_info %p from /usr/lib/dyld symbol table\n",
995 dyld_all_image_infos_addr
);
996 macho_info
->dbg_hdr_addr
= (unsigned long)dyld_all_image_infos_addr
;
1002 if (macho_info
->flags
& MACHO_INFO_MODULE
)
1004 struct macho_module_info
*macho_module_info
;
1005 struct module_format
* modfmt
=
1006 HeapAlloc(GetProcessHeap(), 0, sizeof(struct module_format
) + sizeof(struct macho_module_info
));
1007 if (!modfmt
) goto leave
;
1008 macho_info
->module
= module_new(pcs
, filename
, DMT_MACHO
, FALSE
, load_addr
,
1009 fmap
.segs_size
, 0, calc_crc32(fmap
.fd
));
1010 if (!macho_info
->module
)
1012 HeapFree(GetProcessHeap(), 0, modfmt
);
1015 macho_module_info
= (void*)(modfmt
+ 1);
1016 macho_info
->module
->format_info
[DFI_MACHO
] = modfmt
;
1018 modfmt
->module
= macho_info
->module
;
1019 modfmt
->remove
= NULL
;
1020 modfmt
->loc_compute
= NULL
;
1021 modfmt
->u
.macho_info
= macho_module_info
;
1023 macho_module_info
->load_addr
= load_addr
;
1025 if (dbghelp_options
& SYMOPT_DEFERRED_LOADS
)
1026 macho_info
->module
->module
.SymType
= SymDeferred
;
1027 else if (!macho_load_debug_info(macho_info
->module
, &fmap
))
1030 macho_info
->module
->format_info
[DFI_MACHO
]->u
.macho_info
->in_use
= 1;
1031 macho_info
->module
->format_info
[DFI_MACHO
]->u
.macho_info
->is_loader
= 0;
1032 TRACE("module = %p\n", macho_info
->module
);
1035 if (macho_info
->flags
& MACHO_INFO_NAME
)
1038 ptr
= HeapAlloc(GetProcessHeap(), 0, (lstrlenW(filename
) + 1) * sizeof(WCHAR
));
1041 strcpyW(ptr
, filename
);
1042 macho_info
->module_name
= ptr
;
1045 TRACE("module_name = %p %s\n", macho_info
->module_name
, debugstr_w(macho_info
->module_name
));
1048 macho_unmap_file(&fmap
);
1050 TRACE(" => %d\n", ret
);
1054 /******************************************************************
1055 * macho_load_file_from_path
1056 * Tries to load a Mach-O file from a set of paths (separated by ':')
1058 static BOOL
macho_load_file_from_path(struct process
* pcs
,
1059 const WCHAR
* filename
,
1060 unsigned long load_addr
,
1062 struct macho_info
* macho_info
)
1066 WCHAR
* pathW
= NULL
;
1069 TRACE("(%p/%p, %s, 0x%08lx, %s, %p)\n", pcs
, pcs
->handle
, debugstr_w(filename
), load_addr
,
1070 debugstr_a(path
), macho_info
);
1072 if (!path
) return FALSE
;
1074 len
= MultiByteToWideChar(CP_UNIXCP
, 0, path
, -1, NULL
, 0);
1075 pathW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1076 if (!pathW
) return FALSE
;
1077 MultiByteToWideChar(CP_UNIXCP
, 0, path
, -1, pathW
, len
);
1079 for (s
= pathW
; s
&& *s
; s
= (t
) ? (t
+1) : NULL
)
1081 t
= strchrW(s
, ':');
1083 fn
= HeapAlloc(GetProcessHeap(), 0, (lstrlenW(filename
) + 1 + lstrlenW(s
) + 1) * sizeof(WCHAR
));
1086 strcatW(fn
, S_SlashW
);
1087 strcatW(fn
, filename
);
1088 ret
= macho_load_file(pcs
, fn
, load_addr
, macho_info
);
1089 HeapFree(GetProcessHeap(), 0, fn
);
1091 s
= (t
) ? (t
+1) : NULL
;
1094 TRACE(" => %d\n", ret
);
1095 HeapFree(GetProcessHeap(), 0, pathW
);
1099 /******************************************************************
1100 * macho_load_file_from_dll_path
1102 * Tries to load a Mach-O file from the dll path
1104 static BOOL
macho_load_file_from_dll_path(struct process
* pcs
,
1105 const WCHAR
* filename
,
1106 unsigned long load_addr
,
1107 struct macho_info
* macho_info
)
1110 unsigned int index
= 0;
1113 TRACE("(%p/%p, %s, 0x%08lx, %p)\n", pcs
, pcs
->handle
, debugstr_w(filename
), load_addr
,
1116 while (!ret
&& (path
= wine_dll_enum_load_path( index
++ )))
1121 len
= MultiByteToWideChar(CP_UNIXCP
, 0, path
, -1, NULL
, 0);
1123 name
= HeapAlloc( GetProcessHeap(), 0,
1124 (len
+ lstrlenW(filename
) + 2) * sizeof(WCHAR
) );
1127 MultiByteToWideChar(CP_UNIXCP
, 0, path
, -1, name
, len
);
1128 strcatW( name
, S_SlashW
);
1129 strcatW( name
, filename
);
1130 ret
= macho_load_file(pcs
, name
, load_addr
, macho_info
);
1131 HeapFree( GetProcessHeap(), 0, name
);
1133 TRACE(" => %d\n", ret
);
1137 /******************************************************************
1138 * macho_search_and_load_file
1140 * Lookup a file in standard Mach-O locations, and if found, load it
1142 static BOOL
macho_search_and_load_file(struct process
* pcs
, const WCHAR
* filename
,
1143 unsigned long load_addr
,
1144 struct macho_info
* macho_info
)
1147 struct module
* module
;
1148 static const WCHAR S_libstdcPPW
[] = {'l','i','b','s','t','d','c','+','+','\0'};
1151 TRACE("(%p/%p, %s, 0x%08lx, %p)\n", pcs
, pcs
->handle
, debugstr_w(filename
), load_addr
,
1154 if (filename
== NULL
|| *filename
== '\0') return FALSE
;
1155 if ((module
= module_is_already_loaded(pcs
, filename
)))
1157 macho_info
->module
= module
;
1158 module
->format_info
[DFI_MACHO
]->u
.macho_info
->in_use
= 1;
1159 return module
->module
.SymType
;
1162 if (strstrW(filename
, S_libstdcPPW
)) return FALSE
; /* We know we can't do it */
1164 /* If has no directories, try LD_LIBRARY_PATH first. */
1165 if (!strchrW(filename
, '/'))
1167 ret
= macho_load_file_from_path(pcs
, filename
, load_addr
,
1168 getenv("PATH"), macho_info
);
1170 /* Try DYLD_LIBRARY_PATH, with just the filename (no directories). */
1173 if ((p
= strrchrW(filename
, '/'))) p
++;
1175 ret
= macho_load_file_from_path(pcs
, p
, load_addr
,
1176 getenv("DYLD_LIBRARY_PATH"), macho_info
);
1178 /* Try the path as given. */
1180 ret
= macho_load_file(pcs
, filename
, load_addr
, macho_info
);
1181 /* Try DYLD_FALLBACK_LIBRARY_PATH, with just the filename (no directories). */
1184 ret
= macho_load_file_from_path(pcs
, p
, load_addr
,
1185 getenv("DYLD_FALLBACK_LIBRARY_PATH"), macho_info
);
1187 if (!ret
&& !strchrW(filename
, '/'))
1188 ret
= macho_load_file_from_dll_path(pcs
, filename
, load_addr
, macho_info
);
1193 /******************************************************************
1194 * macho_enum_modules_internal
1196 * Enumerate Mach-O modules from a running process
1198 static BOOL
macho_enum_modules_internal(const struct process
* pcs
,
1199 const WCHAR
* main_name
,
1200 enum_modules_cb cb
, void* user
)
1202 struct dyld_all_image_infos image_infos
;
1203 struct dyld_image_info
* info_array
= NULL
;
1207 WCHAR bufstrW
[MAX_PATH
];
1210 TRACE("(%p/%p, %s, %p, %p)\n", pcs
, pcs
->handle
, debugstr_w(main_name
), cb
,
1213 if (!pcs
->dbg_hdr_addr
||
1214 !ReadProcessMemory(pcs
->handle
, (void*)pcs
->dbg_hdr_addr
,
1215 &image_infos
, sizeof(image_infos
), NULL
) ||
1216 !image_infos
.infoArray
)
1218 TRACE("Process has %u image infos at %p\n", image_infos
.infoArrayCount
, image_infos
.infoArray
);
1220 len
= image_infos
.infoArrayCount
* sizeof(info_array
[0]);
1221 info_array
= HeapAlloc(GetProcessHeap(), 0, len
);
1223 !ReadProcessMemory(pcs
->handle
, image_infos
.infoArray
,
1224 info_array
, len
, NULL
))
1226 TRACE("... read image infos\n");
1228 for (i
= 0; i
< image_infos
.infoArrayCount
; i
++)
1230 if (info_array
[i
].imageFilePath
!= NULL
&&
1231 ReadProcessMemory(pcs
->handle
, info_array
[i
].imageFilePath
, bufstr
, sizeof(bufstr
), NULL
))
1233 bufstr
[sizeof(bufstr
) - 1] = '\0';
1234 TRACE("[%d] image file %s\n", i
, debugstr_a(bufstr
));
1235 MultiByteToWideChar(CP_UNIXCP
, 0, bufstr
, -1, bufstrW
, sizeof(bufstrW
) / sizeof(WCHAR
));
1236 if (main_name
&& !bufstrW
[0]) strcpyW(bufstrW
, main_name
);
1237 if (!cb(bufstrW
, (unsigned long)info_array
[i
].imageLoadAddress
, user
)) break;
1243 HeapFree(GetProcessHeap(), 0, info_array
);
1249 struct process
* pcs
;
1250 struct macho_info macho_info
;
1253 static BOOL
macho_enum_sync_cb(const WCHAR
* name
, unsigned long addr
, void* user
)
1255 struct macho_sync
* ms
= user
;
1257 TRACE("(%s, 0x%08lx, %p)\n", debugstr_w(name
), addr
, user
);
1258 macho_search_and_load_file(ms
->pcs
, name
, addr
, &ms
->macho_info
);
1262 /******************************************************************
1263 * macho_synchronize_module_list
1265 * Rescans the debuggee's modules list and synchronizes it with
1266 * the one from 'pcs', ie:
1267 * - if a module is in debuggee and not in pcs, it's loaded into pcs
1268 * - if a module is in pcs and not in debuggee, it's unloaded from pcs
1270 BOOL
macho_synchronize_module_list(struct process
* pcs
)
1272 struct module
* module
;
1273 struct macho_sync ms
;
1275 TRACE("(%p/%p)\n", pcs
, pcs
->handle
);
1277 for (module
= pcs
->lmodules
; module
; module
= module
->next
)
1279 if (module
->type
== DMT_MACHO
&& !module
->is_virtual
)
1280 module
->format_info
[DFI_MACHO
]->u
.macho_info
->in_use
= 0;
1284 ms
.macho_info
.flags
= MACHO_INFO_MODULE
;
1285 if (!macho_enum_modules_internal(pcs
, NULL
, macho_enum_sync_cb
, &ms
))
1288 module
= pcs
->lmodules
;
1291 if (module
->type
== DMT_MACHO
&& !module
->is_virtual
&&
1292 !module
->format_info
[DFI_MACHO
]->u
.macho_info
->in_use
&&
1293 !module
->format_info
[DFI_MACHO
]->u
.macho_info
->is_loader
)
1295 module_remove(pcs
, module
);
1296 /* restart all over */
1297 module
= pcs
->lmodules
;
1299 else module
= module
->next
;
1304 /******************************************************************
1305 * macho_search_loader
1307 * Lookup in a running Mach-O process the loader, and sets its Mach-O link
1308 * address (for accessing the list of loaded images) in pcs.
1309 * If flags is MACHO_INFO_MODULE, the module for the loader is also
1310 * added as a module into pcs.
1312 static BOOL
macho_search_loader(struct process
* pcs
, struct macho_info
* macho_info
)
1314 return macho_search_and_load_file(pcs
, get_wine_loader_name(), 0, macho_info
);
1317 /******************************************************************
1318 * macho_read_wine_loader_dbg_info
1320 * Try to find a decent wine executable which could have loaded the debuggee
1322 BOOL
macho_read_wine_loader_dbg_info(struct process
* pcs
)
1324 struct macho_info macho_info
;
1326 TRACE("(%p/%p)\n", pcs
, pcs
->handle
);
1327 macho_info
.flags
= MACHO_INFO_DEBUG_HEADER
| MACHO_INFO_MODULE
;
1328 if (!macho_search_loader(pcs
, &macho_info
)) return FALSE
;
1329 macho_info
.module
->format_info
[DFI_MACHO
]->u
.macho_info
->is_loader
= 1;
1330 module_set_module(macho_info
.module
, S_WineLoaderW
);
1331 return (pcs
->dbg_hdr_addr
= macho_info
.dbg_hdr_addr
) != 0;
1334 /******************************************************************
1335 * macho_enum_modules
1337 * Enumerates the Mach-O loaded modules from a running target (hProc)
1338 * This function doesn't require that someone has called SymInitialize
1339 * on this very process.
1341 BOOL
macho_enum_modules(HANDLE hProc
, enum_modules_cb cb
, void* user
)
1344 struct macho_info macho_info
;
1347 TRACE("(%p, %p, %p)\n", hProc
, cb
, user
);
1348 memset(&pcs
, 0, sizeof(pcs
));
1350 macho_info
.flags
= MACHO_INFO_DEBUG_HEADER
| MACHO_INFO_NAME
;
1351 if (!macho_search_loader(&pcs
, &macho_info
)) return FALSE
;
1352 pcs
.dbg_hdr_addr
= macho_info
.dbg_hdr_addr
;
1353 ret
= macho_enum_modules_internal(&pcs
, macho_info
.module_name
, cb
, user
);
1354 HeapFree(GetProcessHeap(), 0, (char*)macho_info
.module_name
);
1360 struct process
* pcs
;
1361 struct macho_info macho_info
;
1366 /******************************************************************
1369 * Callback for macho_load_module, used to walk the list of loaded
1372 static BOOL
macho_load_cb(const WCHAR
* name
, unsigned long addr
, void* user
)
1374 struct macho_load
* ml
= user
;
1377 TRACE("(%s, 0x%08lx, %p)\n", debugstr_w(name
), addr
, user
);
1379 /* memcmp is needed for matches when bufstr contains also version information
1380 * ml->name: libc.so, name: libc.so.6.0
1382 p
= strrchrW(name
, '/');
1384 if (!memcmp(p
, ml
->name
, lstrlenW(ml
->name
) * sizeof(WCHAR
)))
1386 ml
->ret
= macho_search_and_load_file(ml
->pcs
, name
, addr
, &ml
->macho_info
);
1392 /******************************************************************
1395 * Loads a Mach-O module and stores it in process' module list.
1396 * Also, find module real name and load address from
1397 * the real loaded modules list in pcs address space.
1399 struct module
* macho_load_module(struct process
* pcs
, const WCHAR
* name
, unsigned long addr
)
1401 struct macho_load ml
;
1403 TRACE("(%p/%p, %s, 0x%08lx)\n", pcs
, pcs
->handle
, debugstr_w(name
), addr
);
1405 ml
.macho_info
.flags
= MACHO_INFO_MODULE
;
1408 if (pcs
->dbg_hdr_addr
) /* we're debugging a live target */
1411 /* do only the lookup from the filename, not the path (as we lookup module
1412 * name in the process' loaded module list)
1414 ml
.name
= strrchrW(name
, '/');
1415 if (!ml
.name
++) ml
.name
= name
;
1418 if (!macho_enum_modules_internal(pcs
, NULL
, macho_load_cb
, &ml
))
1424 ml
.ret
= macho_search_and_load_file(pcs
, ml
.name
, addr
, &ml
.macho_info
);
1426 if (!ml
.ret
) return NULL
;
1427 assert(ml
.macho_info
.module
);
1428 return ml
.macho_info
.module
;
1431 #else /* HAVE_MACH_O_LOADER_H */
1433 BOOL
macho_synchronize_module_list(struct process
* pcs
)
1438 BOOL
macho_fetch_file_info(const WCHAR
* name
, DWORD_PTR
* base
,
1439 DWORD
* size
, DWORD
* checksum
)
1444 BOOL
macho_read_wine_loader_dbg_info(struct process
* pcs
)
1449 BOOL
macho_enum_modules(HANDLE hProc
, enum_modules_cb cb
, void* user
)
1454 struct module
* macho_load_module(struct process
* pcs
, const WCHAR
* name
, unsigned long addr
)
1459 BOOL
macho_load_debug_info(struct module
* module
, struct macho_file_map
* fmap
)
1463 #endif /* HAVE_MACH_O_LOADER_H */