[DBGHELP]
[reactos.git] / reactos / dll / win32 / dbghelp / macho_module.c
1 /*
2 * File macho_module.c - processing of Mach-O files
3 * Originally based on elf_module.c
4 *
5 * Copyright (C) 1996, Eric Youngdale.
6 * 1999-2007 Eric Pouech
7 * 2009 Ken Thomases, CodeWeavers Inc.
8 *
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.
13 *
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.
18 *
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
22 */
23
24 #include "dbghelp_private.h"
25
26 #ifdef HAVE_MACH_O_LOADER_H
27
28 #include <mach-o/fat.h>
29 #include <mach-o/loader.h>
30 #include <mach-o/nlist.h>
31
32 #ifdef HAVE_MACH_O_DYLD_IMAGES_H
33 #include <mach-o/dyld_images.h>
34 #else
35 struct dyld_image_info {
36 const struct mach_header *imageLoadAddress;
37 const char *imageFilePath;
38 uintptr_t imageFileModDate;
39 };
40
41 struct dyld_all_image_infos {
42 uint32_t version;
43 uint32_t infoArrayCount;
44 const struct dyld_image_info *infoArray;
45 void* notification;
46 int processDetachedFromSharedRegion;
47 };
48 #endif
49
50 #include "winternl.h"
51 #include "wine/library.h"
52 #include "wine/debug.h"
53
54 #ifdef WORDS_BIGENDIAN
55 #define swap_ulong_be_to_host(n) (n)
56 #else
57 #define swap_ulong_be_to_host(n) (RtlUlongByteSwap(n))
58 #endif
59
60 WINE_DEFAULT_DEBUG_CHANNEL(dbghelp_macho);
61
62
63 struct macho_module_info
64 {
65 unsigned long load_addr;
66 unsigned short in_use : 1,
67 is_loader : 1;
68 };
69
70 #define MACHO_INFO_DEBUG_HEADER 0x0001
71 #define MACHO_INFO_MODULE 0x0002
72 #define MACHO_INFO_NAME 0x0004
73
74 struct macho_info
75 {
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) */
80 };
81
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)
85 struct macho_file_map
86 {
87 /* A copy of the Mach-O header for an individual architecture. */
88 struct mach_header mach_header;
89
90 /* The mapped load commands. */
91 const struct load_command* load_commands;
92
93 /* The portion of the file which is this architecture. mach_header was
94 * read from arch_offset. */
95 unsigned arch_offset;
96 unsigned arch_size;
97
98 /* The range of address space covered by all segments. */
99 size_t segs_start;
100 size_t segs_size;
101
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)];
106
107 /* The file. */
108 int fd;
109 };
110
111 static void macho_unmap_file(struct macho_file_map* fmap);
112
113 /******************************************************************
114 * macho_calc_range
115 *
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.
120 */
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)
125 {
126 unsigned pagemask = sysconf( _SC_PAGESIZE ) - 1;
127 unsigned file_offset, misalign;
128
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;
133 if (out_aligned_len)
134 *out_aligned_len = *out_aligned_end - *out_aligned_offset;
135 if (out_misalign)
136 *out_misalign = misalign;
137 }
138
139 /******************************************************************
140 * macho_map_range
141 *
142 * Maps a range (offset, length in bytes) from a Mach-O file into memory
143 */
144 static const char* macho_map_range(const struct macho_file_map* fmap, unsigned offset, unsigned len)
145 {
146 unsigned misalign, aligned_offset, aligned_map_end, map_size;
147 const void* aligned_ptr;
148
149 TRACE("(%p/%d, 0x%08x, 0x%08x)\n", fmap, fmap->fd, offset, len);
150
151 macho_calc_range(fmap, offset, len, &aligned_offset, &aligned_map_end,
152 &map_size, &misalign);
153
154 aligned_ptr = mmap(NULL, map_size, PROT_READ, MAP_PRIVATE, fmap->fd, aligned_offset);
155
156 TRACE("Mapped (0x%08x - 0x%08x) to %p\n", aligned_offset, aligned_map_end, aligned_ptr);
157
158 if (aligned_ptr == MAP_FAILED) return MACHO_NO_MAP;
159 return (const char*)aligned_ptr + misalign;
160 }
161
162 /******************************************************************
163 * macho_unmap_range
164 *
165 * Unmaps a range (offset, length in bytes) of a Mach-O file from memory
166 */
167 static void macho_unmap_range(const void** mapped, const struct macho_file_map* fmap,
168 unsigned offset, unsigned len)
169 {
170 TRACE("(%p, %p/%d, 0x%08x, 0x%08x)\n", mapped, fmap, fmap->fd, offset, len);
171
172 if (mapped && *mapped != MACHO_NO_MAP)
173 {
174 unsigned misalign, aligned_offset, aligned_map_end, map_size;
175 void* aligned_ptr;
176
177 macho_calc_range(fmap, offset, len, &aligned_offset, &aligned_map_end,
178 &map_size, &misalign);
179
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;
185 }
186 }
187
188 /******************************************************************
189 * macho_map_ranges
190 *
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.
194 */
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)
199 {
200 unsigned aligned_offset1, aligned_map_end1;
201 unsigned aligned_offset2, aligned_map_end2;
202
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);
205
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);
208
209 if (aligned_map_end1 < aligned_offset2 || aligned_map_end2 < aligned_offset1)
210 {
211 *mapped1 = macho_map_range(fmap, offset1, len1);
212 if (*mapped1 != MACHO_NO_MAP)
213 {
214 *mapped2 = macho_map_range(fmap, offset2, len2);
215 if (*mapped2 == MACHO_NO_MAP)
216 macho_unmap_range(mapped1, fmap, offset1, len1);
217 }
218 }
219 else
220 {
221 if (offset1 < offset2)
222 {
223 *mapped1 = macho_map_range(fmap, offset1, offset2 + len2 - offset1);
224 if (*mapped1 != MACHO_NO_MAP)
225 *mapped2 = (const char*)*mapped1 + offset2 - offset1;
226 }
227 else
228 {
229 *mapped2 = macho_map_range(fmap, offset2, offset1 + len1 - offset2);
230 if (*mapped2 != MACHO_NO_MAP)
231 *mapped1 = (const char*)*mapped2 + offset1 - offset2;
232 }
233 }
234
235 TRACE(" => %p, %p\n", *mapped1, *mapped2);
236
237 return (*mapped1 != MACHO_NO_MAP) && (*mapped2 != MACHO_NO_MAP);
238 }
239
240 /******************************************************************
241 * macho_unmap_ranges
242 *
243 * Unmaps two ranges (offset, length in bytes) of a Mach-O file
244 * from memory. Use for ranges which were mapped by
245 * macho_map_ranges.
246 */
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)
251 {
252 unsigned aligned_offset1, aligned_map_end1;
253 unsigned aligned_offset2, aligned_map_end2;
254
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);
257
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);
260
261 if (aligned_map_end1 < aligned_offset2 || aligned_map_end2 < aligned_offset1)
262 {
263 macho_unmap_range(mapped1, fmap, offset1, len1);
264 macho_unmap_range(mapped2, fmap, offset2, len2);
265 }
266 else
267 {
268 if (offset1 < offset2)
269 {
270 macho_unmap_range(mapped1, fmap, offset1, offset2 + len2 - offset1);
271 *mapped2 = MACHO_NO_MAP;
272 }
273 else
274 {
275 macho_unmap_range(mapped2, fmap, offset2, offset1 + len1 - offset2);
276 *mapped1 = MACHO_NO_MAP;
277 }
278 }
279 }
280
281 /******************************************************************
282 * macho_map_load_commands
283 *
284 * Maps the load commands from a Mach-O file into memory
285 */
286 static const struct load_command* macho_map_load_commands(struct macho_file_map* fmap)
287 {
288 if (fmap->load_commands == MACHO_NO_MAP)
289 {
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);
293 }
294
295 return fmap->load_commands;
296 }
297
298 /******************************************************************
299 * macho_unmap_load_commands
300 *
301 * Unmaps the load commands of a Mach-O file from memory
302 */
303 static void macho_unmap_load_commands(struct macho_file_map* fmap)
304 {
305 if (fmap->load_commands != MACHO_NO_MAP)
306 {
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);
310 }
311 }
312
313 /******************************************************************
314 * macho_next_load_command
315 *
316 * Advance to the next load command
317 */
318 static const struct load_command* macho_next_load_command(const struct load_command* lc)
319 {
320 return (const struct load_command*)((const char*)lc + lc->cmdsize);
321 }
322
323 /******************************************************************
324 * macho_enum_load_commands
325 *
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
332 * processed.
333 */
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*),
336 void* user)
337 {
338 const struct load_command* lc;
339 int i;
340 int count = 0;
341
342 TRACE("(%p/%d, %u, %p, %p)\n", fmap, fmap->fd, cmd, cb, user);
343
344 if ((lc = macho_map_load_commands(fmap)) == MACHO_NO_MAP) return -1;
345
346 TRACE("%d total commands\n", fmap->mach_header.ncmds);
347
348 for (i = 0; i < fmap->mach_header.ncmds; i++, lc = macho_next_load_command(lc))
349 {
350 int result;
351
352 if (cmd && cmd != lc->cmd) continue;
353 count++;
354
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;
358 }
359
360 return count;
361 }
362
363 /******************************************************************
364 * macho_accum_segs_range
365 *
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.
369 */
370 static int macho_accum_segs_range(struct macho_file_map* fmap,
371 const struct load_command* lc, void* user)
372 {
373 const struct segment_command* sc = (const struct segment_command*)lc;
374 unsigned tmp, page_mask = sysconf( _SC_PAGESIZE ) - 1;
375
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);
380
381 if (!strncmp(sc->segname, "WINE_", 5))
382 {
383 TRACE("Ignoring special Wine segment %s\n", debugstr_an(sc->segname, sizeof(sc->segname)));
384 return 0;
385 }
386 if (!strncmp(sc->segname, "__PAGEZERO", 10))
387 {
388 TRACE("Ignoring __PAGEZERO segment\n");
389 return 0;
390 }
391
392 /* If this segment starts before previously-known earliest, record
393 * new earliest. */
394 if (sc->vmaddr < fmap->segs_start)
395 fmap->segs_start = sc->vmaddr;
396
397 /* If this segment extends beyond previously-known furthest, record
398 * new furthest. */
399 tmp = (sc->vmaddr + sc->vmsize + page_mask) & ~page_mask;
400 if (fmap->segs_size < tmp) fmap->segs_size = tmp;
401
402 TRACE("after: 0x%08x - 0x%08x\n", (unsigned)fmap->segs_start, (unsigned)fmap->segs_size);
403
404 return 0;
405 }
406
407 /******************************************************************
408 * macho_map_file
409 *
410 * Maps a Mach-O file into memory (and checks it's a real Mach-O file)
411 */
412 static BOOL macho_map_file(const WCHAR* filenameW, struct macho_file_map* fmap)
413 {
414 struct fat_header fat_header;
415 struct stat statbuf;
416 int i;
417 char* filename;
418 unsigned len;
419 BOOL ret = FALSE;
420
421 TRACE("(%s, %p)\n", debugstr_w(filenameW), fmap);
422
423 fmap->fd = -1;
424 fmap->load_commands = MACHO_NO_MAP;
425 RtlInitializeBitMap(&fmap->sect_is_code, fmap->sect_is_code_buff, MAX_SECT + 1);
426
427 len = WideCharToMultiByte(CP_UNIXCP, 0, filenameW, -1, NULL, 0, NULL, NULL);
428 if (!(filename = HeapAlloc(GetProcessHeap(), 0, len)))
429 {
430 WARN("failed to allocate filename buffer\n");
431 return FALSE;
432 }
433 WideCharToMultiByte(CP_UNIXCP, 0, filenameW, -1, filename, len, NULL, NULL);
434
435 /* check that the file exists */
436 if (stat(filename, &statbuf) == -1 || S_ISDIR(statbuf.st_mode))
437 {
438 TRACE("stat() failed or %s is directory: %s\n", debugstr_a(filename), strerror(errno));
439 goto done;
440 }
441
442 /* Now open the file, so that we can mmap() it. */
443 if ((fmap->fd = open(filename, O_RDONLY)) == -1)
444 {
445 TRACE("failed to open file %s: %d\n", debugstr_a(filename), errno);
446 goto done;
447 }
448
449 if (read(fmap->fd, &fat_header, sizeof(fat_header)) != sizeof(fat_header))
450 {
451 TRACE("failed to read fat header: %d\n", errno);
452 goto done;
453 }
454 TRACE("... got possible fat header\n");
455
456 /* Fat header is always in big-endian order. */
457 if (swap_ulong_be_to_host(fat_header.magic) == FAT_MAGIC)
458 {
459 int narch = swap_ulong_be_to_host(fat_header.nfat_arch);
460 for (i = 0; i < narch; i++)
461 {
462 struct fat_arch fat_arch;
463 if (read(fmap->fd, &fat_arch, sizeof(fat_arch)) != sizeof(fat_arch))
464 goto done;
465 if (swap_ulong_be_to_host(fat_arch.cputype) == CPU_TYPE_X86)
466 {
467 fmap->arch_offset = swap_ulong_be_to_host(fat_arch.offset);
468 fmap->arch_size = swap_ulong_be_to_host(fat_arch.size);
469 break;
470 }
471 }
472 if (i >= narch) goto done;
473 TRACE("... found x86 arch\n");
474 }
475 else
476 {
477 fmap->arch_offset = 0;
478 fmap->arch_size = statbuf.st_size;
479 TRACE("... not a fat header\n");
480 }
481
482 /* Individual architecture (standalone or within a fat file) is in its native byte order. */
483 lseek(fmap->fd, fmap->arch_offset, SEEK_SET);
484 if (read(fmap->fd, &fmap->mach_header, sizeof(fmap->mach_header)) != sizeof(fmap->mach_header))
485 goto done;
486 TRACE("... got possible Mach header\n");
487 /* and check for a Mach-O header */
488 if (fmap->mach_header.magic != MH_MAGIC ||
489 fmap->mach_header.cputype != CPU_TYPE_X86) goto done;
490 /* Make sure the file type is one of the ones we expect. */
491 switch (fmap->mach_header.filetype)
492 {
493 case MH_EXECUTE:
494 case MH_DYLIB:
495 case MH_DYLINKER:
496 case MH_BUNDLE:
497 break;
498 default:
499 goto done;
500 }
501 TRACE("... verified Mach x86 header\n");
502
503 fmap->segs_size = 0;
504 fmap->segs_start = ~0L;
505
506 if (macho_enum_load_commands(fmap, LC_SEGMENT, macho_accum_segs_range, NULL) < 0)
507 goto done;
508
509 fmap->segs_size -= fmap->segs_start;
510 TRACE("segs_start: 0x%08x, segs_size: 0x%08x\n", (unsigned)fmap->segs_start,
511 (unsigned)fmap->segs_size);
512
513 ret = TRUE;
514 done:
515 if (!ret)
516 macho_unmap_file(fmap);
517 HeapFree(GetProcessHeap(), 0, filename);
518 return ret;
519 }
520
521 /******************************************************************
522 * macho_unmap_file
523 *
524 * Unmaps a Mach-O file from memory (previously mapped with macho_map_file)
525 */
526 static void macho_unmap_file(struct macho_file_map* fmap)
527 {
528 TRACE("(%p/%d)\n", fmap, fmap->fd);
529 if (fmap->fd != -1)
530 {
531 macho_unmap_load_commands(fmap);
532 close(fmap->fd);
533 fmap->fd = -1;
534 }
535 }
536
537 /******************************************************************
538 * macho_fill_sect_is_code
539 *
540 * Callback for macho_enum_load_commands. Determines which segments
541 * of a Mach-O file contain code. All commands are expected to be
542 * of LC_SEGMENT type.
543 */
544 static int macho_fill_sect_is_code(struct macho_file_map* fmap,
545 const struct load_command* lc, void* user)
546 {
547 const struct segment_command* sc = (const struct segment_command*)lc;
548 const struct section* sections;
549 int* cursect = user;
550 int i;
551
552 TRACE("(%p/%d, %p, %p/%d) scanning %u sections\n", fmap, fmap->fd, lc,
553 cursect, *cursect, sc->nsects);
554
555 sections = (const struct section*)(sc + 1);
556 for (i = 0; i < sc->nsects; i++)
557 {
558 if (*cursect > MAX_SECT) return -1;
559 (*cursect)++;
560
561 if (!(sections[i].flags & SECTION_TYPE) &&
562 (sections[i].flags & (S_ATTR_PURE_INSTRUCTIONS|S_ATTR_SOME_INSTRUCTIONS)))
563 RtlSetBits(&fmap->sect_is_code, *cursect, 1);
564 else
565 RtlClearBits(&fmap->sect_is_code, *cursect, 1);
566 TRACE("Section %d (%d of this segment) is%s code\n", *cursect, i,
567 (RtlAreBitsSet(&fmap->sect_is_code, *cursect, 1) ? "" : " not"));
568 }
569
570 return 0;
571 }
572
573 /******************************************************************
574 * macho_sect_is_code
575 *
576 * Checks if a section, identified by sectidx which is a 1-based
577 * index into the sections of all segments, in order of load
578 * commands, contains code.
579 */
580 static BOOL macho_sect_is_code(struct macho_file_map* fmap, unsigned char sectidx)
581 {
582 TRACE("(%p/%d, %u)\n", fmap, fmap->fd, sectidx);
583
584 if (!RtlAreBitsSet(&fmap->sect_is_code, 0, 1))
585 {
586 int cursect = 0;
587 if (macho_enum_load_commands(fmap, LC_SEGMENT, macho_fill_sect_is_code, &cursect) < 0)
588 WARN("Couldn't load sect_is_code map\n");
589 RtlSetBits(&fmap->sect_is_code, 0, 1);
590 }
591
592 return RtlAreBitsSet(&fmap->sect_is_code, sectidx, 1);
593 }
594
595 struct symtab_elt
596 {
597 struct hash_table_elt ht_elt;
598 struct symt_compiland* compiland;
599 unsigned long addr;
600 unsigned char is_code:1,
601 is_public:1,
602 is_global:1,
603 used:1;
604 };
605
606 struct macho_debug_info
607 {
608 struct macho_file_map* fmap;
609 struct module* module;
610 struct pool pool;
611 struct hash_table ht_symtab;
612 };
613
614 /******************************************************************
615 * macho_stabs_def_cb
616 *
617 * Callback for stabs_parse. Collect symbol definitions.
618 */
619 static void macho_stabs_def_cb(struct module* module, unsigned long load_offset,
620 const char* name, unsigned long offset,
621 BOOL is_public, BOOL is_global, unsigned char sectidx,
622 struct symt_compiland* compiland, void* user)
623 {
624 struct macho_debug_info* mdi = user;
625 struct symtab_elt* ste;
626
627 TRACE("(%p, 0x%08lx, %s, 0x%08lx, %d, %d, %u, %p, %p/%p/%d)\n", module, load_offset,
628 debugstr_a(name), offset, is_public, is_global, sectidx,
629 compiland, mdi, mdi->fmap, mdi->fmap->fd);
630
631 /* Defer the creation of new non-debugging symbols until after we've
632 * finished parsing the stabs. */
633 ste = pool_alloc(&mdi->pool, sizeof(*ste));
634 ste->ht_elt.name = pool_strdup(&mdi->pool, name);
635 ste->compiland = compiland;
636 ste->addr = load_offset + offset;
637 ste->is_code = !!macho_sect_is_code(mdi->fmap, sectidx);
638 ste->is_public = !!is_public;
639 ste->is_global = !!is_global;
640 ste->used = 0;
641 hash_table_add(&mdi->ht_symtab, &ste->ht_elt);
642 }
643
644 /******************************************************************
645 * macho_parse_symtab
646 *
647 * Callback for macho_enum_load_commands. Processes the LC_SYMTAB
648 * load commands from the Mach-O file.
649 */
650 static int macho_parse_symtab(struct macho_file_map* fmap,
651 const struct load_command* lc, void* user)
652 {
653 const struct symtab_command* sc = (const struct symtab_command*)lc;
654 struct macho_debug_info* mdi = user;
655 const struct nlist* stab;
656 const char* stabstr;
657 int ret = 0;
658
659 TRACE("(%p/%d, %p, %p) %u syms at 0x%08x, strings 0x%08x - 0x%08x\n", fmap, fmap->fd, lc,
660 user, sc->nsyms, sc->symoff, sc->stroff, sc->stroff + sc->strsize);
661
662 if (!macho_map_ranges(fmap, sc->symoff, sc->nsyms * sizeof(struct nlist),
663 sc->stroff, sc->strsize, (const void**)&stab, (const void**)&stabstr))
664 return 0;
665
666 if (!stabs_parse(mdi->module,
667 mdi->module->format_info[DFI_MACHO]->u.macho_info->load_addr - fmap->segs_start,
668 stab, sc->nsyms * sizeof(struct nlist),
669 stabstr, sc->strsize, macho_stabs_def_cb, mdi))
670 ret = -1;
671
672 macho_unmap_ranges(fmap, sc->symoff, sc->nsyms * sizeof(struct nlist),
673 sc->stroff, sc->strsize, (const void**)&stab, (const void**)&stabstr);
674
675 return ret;
676 }
677
678 /******************************************************************
679 * macho_finish_stabs
680 *
681 * Integrate the non-debugging symbols we've gathered into the
682 * symbols that were generated during stabs parsing.
683 */
684 static void macho_finish_stabs(struct module* module, struct hash_table* ht_symtab)
685 {
686 struct hash_table_iter hti_ours;
687 struct symtab_elt* ste;
688 BOOL adjusted = FALSE;
689
690 TRACE("(%p, %p)\n", module, ht_symtab);
691
692 /* For each of our non-debugging symbols, see if it can provide some
693 * missing details to one of the module's known symbols. */
694 hash_table_iter_init(ht_symtab, &hti_ours, NULL);
695 while ((ste = hash_table_iter_up(&hti_ours)))
696 {
697 struct hash_table_iter hti_modules;
698 void* ptr;
699 struct symt_ht* sym;
700 struct symt_function* func;
701 struct symt_data* data;
702
703 hash_table_iter_init(&module->ht_symbols, &hti_modules, ste->ht_elt.name);
704 while ((ptr = hash_table_iter_up(&hti_modules)))
705 {
706 sym = GET_ENTRY(ptr, struct symt_ht, hash_elt);
707
708 if (strcmp(sym->hash_elt.name, ste->ht_elt.name))
709 continue;
710
711 switch (sym->symt.tag)
712 {
713 case SymTagFunction:
714 func = (struct symt_function*)sym;
715 if (func->address == module->format_info[DFI_MACHO]->u.macho_info->load_addr)
716 {
717 TRACE("Adjusting function %p/%s!%s from 0x%08lx to 0x%08lx\n", func,
718 debugstr_w(module->module.ModuleName), sym->hash_elt.name,
719 func->address, ste->addr);
720 func->address = ste->addr;
721 adjusted = TRUE;
722 }
723 if (func->address == ste->addr)
724 ste->used = 1;
725 break;
726 case SymTagData:
727 data = (struct symt_data*)sym;
728 switch (data->kind)
729 {
730 case DataIsGlobal:
731 case DataIsFileStatic:
732 if (data->u.var.offset == module->format_info[DFI_MACHO]->u.macho_info->load_addr)
733 {
734 TRACE("Adjusting data symbol %p/%s!%s from 0x%08lx to 0x%08lx\n",
735 data, debugstr_w(module->module.ModuleName), sym->hash_elt.name,
736 data->u.var.offset, ste->addr);
737 data->u.var.offset = ste->addr;
738 adjusted = TRUE;
739 }
740 if (data->u.var.offset == ste->addr)
741 {
742 enum DataKind new_kind;
743
744 new_kind = ste->is_global ? DataIsGlobal : DataIsFileStatic;
745 if (data->kind != new_kind)
746 {
747 WARN("Changing kind for %p/%s!%s from %d to %d\n", sym,
748 debugstr_w(module->module.ModuleName), sym->hash_elt.name,
749 (int)data->kind, (int)new_kind);
750 data->kind = new_kind;
751 adjusted = TRUE;
752 }
753 ste->used = 1;
754 }
755 break;
756 default:;
757 }
758 break;
759 default:
760 TRACE("Ignoring tag %u\n", sym->symt.tag);
761 break;
762 }
763 }
764 }
765
766 if (adjusted)
767 {
768 /* since we may have changed some addresses, mark the module to be resorted */
769 module->sortlist_valid = FALSE;
770 }
771
772 /* Mark any of our non-debugging symbols which fall on an already-used
773 * address as "used". This allows us to skip them in the next loop,
774 * below. We do this in separate loops because symt_new_* marks the
775 * list as needing sorting and symt_find_nearest sorts if needed,
776 * causing thrashing. */
777 if (!(dbghelp_options & SYMOPT_PUBLICS_ONLY))
778 {
779 hash_table_iter_init(ht_symtab, &hti_ours, NULL);
780 while ((ste = hash_table_iter_up(&hti_ours)))
781 {
782 struct symt_ht* sym;
783 ULONG64 addr;
784
785 if (ste->used) continue;
786
787 sym = symt_find_nearest(module, ste->addr);
788 if (sym)
789 symt_get_address(&sym->symt, &addr);
790 if (sym && ste->addr == addr)
791 {
792 ULONG64 size = 0;
793 DWORD kind = -1;
794
795 ste->used = 1;
796
797 /* If neither symbol has a correct size (ours never does), we
798 * consider them both to be markers. No warning is needed in
799 * that case.
800 * Also, we check that we don't have two symbols, one local, the other
801 * global, which is legal.
802 */
803 symt_get_info(module, &sym->symt, TI_GET_LENGTH, &size);
804 symt_get_info(module, &sym->symt, TI_GET_DATAKIND, &kind);
805 if (size && kind == (ste->is_global ? DataIsGlobal : DataIsFileStatic))
806 FIXME("Duplicate in %s: %s<%08lx> %s<%s-%s>\n",
807 debugstr_w(module->module.ModuleName),
808 ste->ht_elt.name, ste->addr,
809 sym->hash_elt.name,
810 wine_dbgstr_longlong(addr), wine_dbgstr_longlong(size));
811 }
812 }
813 }
814
815 /* For any of our remaining non-debugging symbols which have no match
816 * among the module's known symbols, add them as new symbols. */
817 hash_table_iter_init(ht_symtab, &hti_ours, NULL);
818 while ((ste = hash_table_iter_up(&hti_ours)))
819 {
820 if (!(dbghelp_options & SYMOPT_PUBLICS_ONLY) && !ste->used)
821 {
822 if (ste->is_code)
823 {
824 symt_new_function(module, ste->compiland, ste->ht_elt.name,
825 ste->addr, 0, NULL);
826 }
827 else
828 {
829 struct location loc;
830
831 loc.kind = loc_absolute;
832 loc.reg = 0;
833 loc.offset = ste->addr;
834 symt_new_global_variable(module, ste->compiland, ste->ht_elt.name,
835 !ste->is_global, loc, 0, NULL);
836 }
837
838 ste->used = 1;
839 }
840
841 if (ste->is_public && !(dbghelp_options & SYMOPT_NO_PUBLICS))
842 {
843 symt_new_public(module, ste->compiland, ste->ht_elt.name, ste->addr, 0);
844 }
845 }
846 }
847
848 /******************************************************************
849 * macho_load_debug_info_from_map
850 *
851 * Loads the symbolic information from a Mach-O module.
852 * Returns
853 * FALSE if the file doesn't contain symbolic info (or this info
854 * cannot be read or parsed)
855 * TRUE on success
856 */
857 static BOOL macho_load_debug_info_from_map(struct module* module,
858 struct macho_file_map* fmap)
859 {
860 BOOL ret = FALSE;
861 struct macho_debug_info mdi;
862 int result;
863
864 TRACE("(%p, %p/%d)\n", module, fmap, fmap->fd);
865
866 module->module.SymType = SymExport;
867
868 mdi.fmap = fmap;
869 mdi.module = module;
870 pool_init(&mdi.pool, 65536);
871 hash_table_init(&mdi.pool, &mdi.ht_symtab, 256);
872 result = macho_enum_load_commands(fmap, LC_SYMTAB, macho_parse_symtab, &mdi);
873 if (result > 0)
874 ret = TRUE;
875 else if (result < 0)
876 WARN("Couldn't correctly read stabs\n");
877
878 macho_finish_stabs(module, &mdi.ht_symtab);
879
880 pool_destroy(&mdi.pool);
881 return ret;
882 }
883
884 /******************************************************************
885 * macho_load_debug_info
886 *
887 * Loads Mach-O debugging information from the module image file.
888 */
889 BOOL macho_load_debug_info(struct module* module, struct macho_file_map* fmap)
890 {
891 BOOL ret = TRUE;
892 struct macho_file_map my_fmap;
893
894 TRACE("(%p, %p/%d)\n", module, fmap, fmap ? fmap->fd : -1);
895
896 if (module->type != DMT_MACHO || !module->format_info[DFI_MACHO]->u.macho_info)
897 {
898 ERR("Bad Mach-O module '%s'\n", debugstr_w(module->module.LoadedImageName));
899 return FALSE;
900 }
901
902 if (!fmap)
903 {
904 fmap = &my_fmap;
905 ret = macho_map_file(module->module.LoadedImageName, fmap);
906 }
907 if (ret)
908 ret = macho_load_debug_info_from_map(module, fmap);
909
910 if (fmap == &my_fmap) macho_unmap_file(fmap);
911 return ret;
912 }
913
914 /******************************************************************
915 * macho_fetch_file_info
916 *
917 * Gathers some more information for a Mach-O module from a given file
918 */
919 BOOL macho_fetch_file_info(const WCHAR* name, DWORD_PTR* base,
920 DWORD* size, DWORD* checksum)
921 {
922 struct macho_file_map fmap;
923
924 TRACE("(%s, %p, %p, %p)\n", debugstr_w(name), base, size, checksum);
925
926 if (!macho_map_file(name, &fmap)) return FALSE;
927 if (base) *base = fmap.segs_start;
928 *size = fmap.segs_size;
929 *checksum = calc_crc32(fmap.fd);
930 macho_unmap_file(&fmap);
931 return TRUE;
932 }
933
934 /******************************************************************
935 * macho_load_file
936 *
937 * Loads the information for Mach-O module stored in 'filename'.
938 * The module has been loaded at 'load_addr' address.
939 * returns
940 * FALSE if the file cannot be found/opened or if the file doesn't
941 * contain symbolic info (or this info cannot be read or parsed)
942 * TRUE on success
943 */
944 static BOOL macho_load_file(struct process* pcs, const WCHAR* filename,
945 unsigned long load_addr, struct macho_info* macho_info)
946 {
947 BOOL ret = TRUE;
948 struct macho_file_map fmap;
949
950 TRACE("(%p/%p, %s, 0x%08lx, %p/0x%08x)\n", pcs, pcs->handle, debugstr_w(filename),
951 load_addr, macho_info, macho_info->flags);
952
953 if (!macho_map_file(filename, &fmap)) return FALSE;
954
955 /* Find the dynamic loader's table of images loaded into the process.
956 */
957 if (macho_info->flags & MACHO_INFO_DEBUG_HEADER)
958 {
959 PROCESS_BASIC_INFORMATION pbi;
960 NTSTATUS status;
961
962 ret = FALSE;
963
964 /* Get address of PEB */
965 status = NtQueryInformationProcess(pcs->handle, ProcessBasicInformation,
966 &pbi, sizeof(pbi), NULL);
967 if (status == STATUS_SUCCESS)
968 {
969 ULONG dyld_image_info;
970
971 /* Read dyld image info address from PEB */
972 if (ReadProcessMemory(pcs->handle, &pbi.PebBaseAddress->Reserved,
973 &dyld_image_info, sizeof(dyld_image_info), NULL))
974 {
975 TRACE("got dyld_image_info 0x%08x from PEB %p MacDyldImageInfo %p\n",
976 dyld_image_info, pbi.PebBaseAddress, &pbi.PebBaseAddress->Reserved);
977 macho_info->dbg_hdr_addr = dyld_image_info;
978 ret = TRUE;
979 }
980 }
981
982 if (!ret)
983 {
984 static void* dyld_all_image_infos_addr;
985
986 /* Our next best guess is that dyld was loaded at its base address
987 and we can find the dyld image infos address by looking up its symbol. */
988 if (!dyld_all_image_infos_addr)
989 {
990 struct nlist nl[2];
991 memset(nl, 0, sizeof(nl));
992 nl[0].n_un.n_name = (char*)"_dyld_all_image_infos";
993 if (!nlist("/usr/lib/dyld", nl))
994 dyld_all_image_infos_addr = (void*)nl[0].n_value;
995 }
996
997 if (dyld_all_image_infos_addr)
998 {
999 TRACE("got dyld_image_info %p from /usr/lib/dyld symbol table\n",
1000 dyld_all_image_infos_addr);
1001 macho_info->dbg_hdr_addr = (unsigned long)dyld_all_image_infos_addr;
1002 ret = TRUE;
1003 }
1004 }
1005 }
1006
1007 if (macho_info->flags & MACHO_INFO_MODULE)
1008 {
1009 struct macho_module_info *macho_module_info;
1010 struct module_format* modfmt =
1011 HeapAlloc(GetProcessHeap(), 0, sizeof(struct module_format) + sizeof(struct macho_module_info));
1012 if (!modfmt) goto leave;
1013 if (!load_addr)
1014 load_addr = fmap.segs_start;
1015 macho_info->module = module_new(pcs, filename, DMT_MACHO, FALSE, load_addr,
1016 fmap.segs_size, 0, calc_crc32(fmap.fd));
1017 if (!macho_info->module)
1018 {
1019 HeapFree(GetProcessHeap(), 0, modfmt);
1020 goto leave;
1021 }
1022 macho_module_info = (void*)(modfmt + 1);
1023 macho_info->module->format_info[DFI_MACHO] = modfmt;
1024
1025 modfmt->module = macho_info->module;
1026 modfmt->remove = NULL;
1027 modfmt->loc_compute = NULL;
1028 modfmt->u.macho_info = macho_module_info;
1029
1030 macho_module_info->load_addr = load_addr;
1031
1032 if (dbghelp_options & SYMOPT_DEFERRED_LOADS)
1033 macho_info->module->module.SymType = SymDeferred;
1034 else if (!macho_load_debug_info(macho_info->module, &fmap))
1035 ret = FALSE;
1036
1037 macho_info->module->format_info[DFI_MACHO]->u.macho_info->in_use = 1;
1038 macho_info->module->format_info[DFI_MACHO]->u.macho_info->is_loader = 0;
1039 TRACE("module = %p\n", macho_info->module);
1040 }
1041
1042 if (macho_info->flags & MACHO_INFO_NAME)
1043 {
1044 WCHAR* ptr;
1045 ptr = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(filename) + 1) * sizeof(WCHAR));
1046 if (ptr)
1047 {
1048 strcpyW(ptr, filename);
1049 macho_info->module_name = ptr;
1050 }
1051 else ret = FALSE;
1052 TRACE("module_name = %p %s\n", macho_info->module_name, debugstr_w(macho_info->module_name));
1053 }
1054 leave:
1055 macho_unmap_file(&fmap);
1056
1057 TRACE(" => %d\n", ret);
1058 return ret;
1059 }
1060
1061 /******************************************************************
1062 * macho_load_file_from_path
1063 * Tries to load a Mach-O file from a set of paths (separated by ':')
1064 */
1065 static BOOL macho_load_file_from_path(struct process* pcs,
1066 const WCHAR* filename,
1067 unsigned long load_addr,
1068 const char* path,
1069 struct macho_info* macho_info)
1070 {
1071 BOOL ret = FALSE;
1072 WCHAR *s, *t, *fn;
1073 WCHAR* pathW = NULL;
1074 unsigned len;
1075
1076 TRACE("(%p/%p, %s, 0x%08lx, %s, %p)\n", pcs, pcs->handle, debugstr_w(filename), load_addr,
1077 debugstr_a(path), macho_info);
1078
1079 if (!path) return FALSE;
1080
1081 len = MultiByteToWideChar(CP_UNIXCP, 0, path, -1, NULL, 0);
1082 pathW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1083 if (!pathW) return FALSE;
1084 MultiByteToWideChar(CP_UNIXCP, 0, path, -1, pathW, len);
1085
1086 for (s = pathW; s && *s; s = (t) ? (t+1) : NULL)
1087 {
1088 t = strchrW(s, ':');
1089 if (t) *t = '\0';
1090 fn = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(filename) + 1 + lstrlenW(s) + 1) * sizeof(WCHAR));
1091 if (!fn) break;
1092 strcpyW(fn, s);
1093 strcatW(fn, S_SlashW);
1094 strcatW(fn, filename);
1095 ret = macho_load_file(pcs, fn, load_addr, macho_info);
1096 HeapFree(GetProcessHeap(), 0, fn);
1097 if (ret) break;
1098 s = (t) ? (t+1) : NULL;
1099 }
1100
1101 TRACE(" => %d\n", ret);
1102 HeapFree(GetProcessHeap(), 0, pathW);
1103 return ret;
1104 }
1105
1106 /******************************************************************
1107 * macho_load_file_from_dll_path
1108 *
1109 * Tries to load a Mach-O file from the dll path
1110 */
1111 static BOOL macho_load_file_from_dll_path(struct process* pcs,
1112 const WCHAR* filename,
1113 unsigned long load_addr,
1114 struct macho_info* macho_info)
1115 {
1116 BOOL ret = FALSE;
1117 unsigned int index = 0;
1118 const char *path;
1119
1120 TRACE("(%p/%p, %s, 0x%08lx, %p)\n", pcs, pcs->handle, debugstr_w(filename), load_addr,
1121 macho_info);
1122
1123 while (!ret && (path = wine_dll_enum_load_path( index++ )))
1124 {
1125 WCHAR *name;
1126 unsigned len;
1127
1128 len = MultiByteToWideChar(CP_UNIXCP, 0, path, -1, NULL, 0);
1129
1130 name = HeapAlloc( GetProcessHeap(), 0,
1131 (len + lstrlenW(filename) + 2) * sizeof(WCHAR) );
1132
1133 if (!name) break;
1134 MultiByteToWideChar(CP_UNIXCP, 0, path, -1, name, len);
1135 strcatW( name, S_SlashW );
1136 strcatW( name, filename );
1137 ret = macho_load_file(pcs, name, load_addr, macho_info);
1138 HeapFree( GetProcessHeap(), 0, name );
1139 }
1140 TRACE(" => %d\n", ret);
1141 return ret;
1142 }
1143
1144 /******************************************************************
1145 * macho_search_and_load_file
1146 *
1147 * Lookup a file in standard Mach-O locations, and if found, load it
1148 */
1149 static BOOL macho_search_and_load_file(struct process* pcs, const WCHAR* filename,
1150 unsigned long load_addr,
1151 struct macho_info* macho_info)
1152 {
1153 BOOL ret = FALSE;
1154 struct module* module;
1155 static const WCHAR S_libstdcPPW[] = {'l','i','b','s','t','d','c','+','+','\0'};
1156 const WCHAR* p;
1157
1158 TRACE("(%p/%p, %s, 0x%08lx, %p)\n", pcs, pcs->handle, debugstr_w(filename), load_addr,
1159 macho_info);
1160
1161 if (filename == NULL || *filename == '\0') return FALSE;
1162 if ((module = module_is_already_loaded(pcs, filename)))
1163 {
1164 macho_info->module = module;
1165 module->format_info[DFI_MACHO]->u.macho_info->in_use = 1;
1166 return module->module.SymType;
1167 }
1168
1169 if (strstrW(filename, S_libstdcPPW)) return FALSE; /* We know we can't do it */
1170
1171 /* If has no directories, try LD_LIBRARY_PATH first. */
1172 if (!strchrW(filename, '/'))
1173 {
1174 ret = macho_load_file_from_path(pcs, filename, load_addr,
1175 getenv("PATH"), macho_info);
1176 }
1177 /* Try DYLD_LIBRARY_PATH, with just the filename (no directories). */
1178 if (!ret)
1179 {
1180 if ((p = strrchrW(filename, '/'))) p++;
1181 else p = filename;
1182 ret = macho_load_file_from_path(pcs, p, load_addr,
1183 getenv("DYLD_LIBRARY_PATH"), macho_info);
1184 }
1185 /* Try the path as given. */
1186 if (!ret)
1187 ret = macho_load_file(pcs, filename, load_addr, macho_info);
1188 /* Try DYLD_FALLBACK_LIBRARY_PATH, with just the filename (no directories). */
1189 if (!ret)
1190 {
1191 ret = macho_load_file_from_path(pcs, p, load_addr,
1192 getenv("DYLD_FALLBACK_LIBRARY_PATH"), macho_info);
1193 }
1194 if (!ret && !strchrW(filename, '/'))
1195 ret = macho_load_file_from_dll_path(pcs, filename, load_addr, macho_info);
1196
1197 return ret;
1198 }
1199
1200 /******************************************************************
1201 * macho_enum_modules_internal
1202 *
1203 * Enumerate Mach-O modules from a running process
1204 */
1205 static BOOL macho_enum_modules_internal(const struct process* pcs,
1206 const WCHAR* main_name,
1207 enum_modules_cb cb, void* user)
1208 {
1209 struct dyld_all_image_infos image_infos;
1210 struct dyld_image_info* info_array = NULL;
1211 unsigned long len;
1212 int i;
1213 char bufstr[256];
1214 WCHAR bufstrW[MAX_PATH];
1215 BOOL ret = FALSE;
1216
1217 TRACE("(%p/%p, %s, %p, %p)\n", pcs, pcs->handle, debugstr_w(main_name), cb,
1218 user);
1219
1220 if (!pcs->dbg_hdr_addr ||
1221 !ReadProcessMemory(pcs->handle, (void*)pcs->dbg_hdr_addr,
1222 &image_infos, sizeof(image_infos), NULL) ||
1223 !image_infos.infoArray)
1224 goto done;
1225 TRACE("Process has %u image infos at %p\n", image_infos.infoArrayCount, image_infos.infoArray);
1226
1227 len = image_infos.infoArrayCount * sizeof(info_array[0]);
1228 info_array = HeapAlloc(GetProcessHeap(), 0, len);
1229 if (!info_array ||
1230 !ReadProcessMemory(pcs->handle, image_infos.infoArray,
1231 info_array, len, NULL))
1232 goto done;
1233 TRACE("... read image infos\n");
1234
1235 for (i = 0; i < image_infos.infoArrayCount; i++)
1236 {
1237 if (info_array[i].imageFilePath != NULL &&
1238 ReadProcessMemory(pcs->handle, info_array[i].imageFilePath, bufstr, sizeof(bufstr), NULL))
1239 {
1240 bufstr[sizeof(bufstr) - 1] = '\0';
1241 TRACE("[%d] image file %s\n", i, debugstr_a(bufstr));
1242 MultiByteToWideChar(CP_UNIXCP, 0, bufstr, -1, bufstrW, sizeof(bufstrW) / sizeof(WCHAR));
1243 if (main_name && !bufstrW[0]) strcpyW(bufstrW, main_name);
1244 if (!cb(bufstrW, (unsigned long)info_array[i].imageLoadAddress, user)) break;
1245 }
1246 }
1247
1248 ret = TRUE;
1249 done:
1250 HeapFree(GetProcessHeap(), 0, info_array);
1251 return ret;
1252 }
1253
1254 struct macho_sync
1255 {
1256 struct process* pcs;
1257 struct macho_info macho_info;
1258 };
1259
1260 static BOOL macho_enum_sync_cb(const WCHAR* name, unsigned long addr, void* user)
1261 {
1262 struct macho_sync* ms = user;
1263
1264 TRACE("(%s, 0x%08lx, %p)\n", debugstr_w(name), addr, user);
1265 macho_search_and_load_file(ms->pcs, name, addr, &ms->macho_info);
1266 return TRUE;
1267 }
1268
1269 /******************************************************************
1270 * macho_synchronize_module_list
1271 *
1272 * Rescans the debuggee's modules list and synchronizes it with
1273 * the one from 'pcs', ie:
1274 * - if a module is in debuggee and not in pcs, it's loaded into pcs
1275 * - if a module is in pcs and not in debuggee, it's unloaded from pcs
1276 */
1277 BOOL macho_synchronize_module_list(struct process* pcs)
1278 {
1279 struct module* module;
1280 struct macho_sync ms;
1281
1282 TRACE("(%p/%p)\n", pcs, pcs->handle);
1283
1284 for (module = pcs->lmodules; module; module = module->next)
1285 {
1286 if (module->type == DMT_MACHO && !module->is_virtual)
1287 module->format_info[DFI_MACHO]->u.macho_info->in_use = 0;
1288 }
1289
1290 ms.pcs = pcs;
1291 ms.macho_info.flags = MACHO_INFO_MODULE;
1292 if (!macho_enum_modules_internal(pcs, NULL, macho_enum_sync_cb, &ms))
1293 return FALSE;
1294
1295 module = pcs->lmodules;
1296 while (module)
1297 {
1298 if (module->type == DMT_MACHO && !module->is_virtual &&
1299 !module->format_info[DFI_MACHO]->u.macho_info->in_use &&
1300 !module->format_info[DFI_MACHO]->u.macho_info->is_loader)
1301 {
1302 module_remove(pcs, module);
1303 /* restart all over */
1304 module = pcs->lmodules;
1305 }
1306 else module = module->next;
1307 }
1308 return TRUE;
1309 }
1310
1311 /******************************************************************
1312 * macho_search_loader
1313 *
1314 * Lookup in a running Mach-O process the loader, and sets its Mach-O link
1315 * address (for accessing the list of loaded images) in pcs.
1316 * If flags is MACHO_INFO_MODULE, the module for the loader is also
1317 * added as a module into pcs.
1318 */
1319 static BOOL macho_search_loader(struct process* pcs, struct macho_info* macho_info)
1320 {
1321 return macho_search_and_load_file(pcs, get_wine_loader_name(), 0, macho_info);
1322 }
1323
1324 /******************************************************************
1325 * macho_read_wine_loader_dbg_info
1326 *
1327 * Try to find a decent wine executable which could have loaded the debuggee
1328 */
1329 BOOL macho_read_wine_loader_dbg_info(struct process* pcs)
1330 {
1331 struct macho_info macho_info;
1332
1333 TRACE("(%p/%p)\n", pcs, pcs->handle);
1334 macho_info.flags = MACHO_INFO_DEBUG_HEADER | MACHO_INFO_MODULE;
1335 if (!macho_search_loader(pcs, &macho_info)) return FALSE;
1336 macho_info.module->format_info[DFI_MACHO]->u.macho_info->is_loader = 1;
1337 module_set_module(macho_info.module, S_WineLoaderW);
1338 return (pcs->dbg_hdr_addr = macho_info.dbg_hdr_addr) != 0;
1339 }
1340
1341 /******************************************************************
1342 * macho_enum_modules
1343 *
1344 * Enumerates the Mach-O loaded modules from a running target (hProc)
1345 * This function doesn't require that someone has called SymInitialize
1346 * on this very process.
1347 */
1348 BOOL macho_enum_modules(HANDLE hProc, enum_modules_cb cb, void* user)
1349 {
1350 struct process pcs;
1351 struct macho_info macho_info;
1352 BOOL ret;
1353
1354 TRACE("(%p, %p, %p)\n", hProc, cb, user);
1355 memset(&pcs, 0, sizeof(pcs));
1356 pcs.handle = hProc;
1357 macho_info.flags = MACHO_INFO_DEBUG_HEADER | MACHO_INFO_NAME;
1358 if (!macho_search_loader(&pcs, &macho_info)) return FALSE;
1359 pcs.dbg_hdr_addr = macho_info.dbg_hdr_addr;
1360 ret = macho_enum_modules_internal(&pcs, macho_info.module_name, cb, user);
1361 HeapFree(GetProcessHeap(), 0, (char*)macho_info.module_name);
1362 return ret;
1363 }
1364
1365 struct macho_load
1366 {
1367 struct process* pcs;
1368 struct macho_info macho_info;
1369 const WCHAR* name;
1370 BOOL ret;
1371 };
1372
1373 /******************************************************************
1374 * macho_load_cb
1375 *
1376 * Callback for macho_load_module, used to walk the list of loaded
1377 * modules.
1378 */
1379 static BOOL macho_load_cb(const WCHAR* name, unsigned long addr, void* user)
1380 {
1381 struct macho_load* ml = user;
1382 const WCHAR* p;
1383
1384 TRACE("(%s, 0x%08lx, %p)\n", debugstr_w(name), addr, user);
1385
1386 /* memcmp is needed for matches when bufstr contains also version information
1387 * ml->name: libc.so, name: libc.so.6.0
1388 */
1389 p = strrchrW(name, '/');
1390 if (!p++) p = name;
1391 if (!memcmp(p, ml->name, lstrlenW(ml->name) * sizeof(WCHAR)))
1392 {
1393 ml->ret = macho_search_and_load_file(ml->pcs, name, addr, &ml->macho_info);
1394 return FALSE;
1395 }
1396 return TRUE;
1397 }
1398
1399 /******************************************************************
1400 * macho_load_module
1401 *
1402 * Loads a Mach-O module and stores it in process' module list.
1403 * Also, find module real name and load address from
1404 * the real loaded modules list in pcs address space.
1405 */
1406 struct module* macho_load_module(struct process* pcs, const WCHAR* name, unsigned long addr)
1407 {
1408 struct macho_load ml;
1409
1410 TRACE("(%p/%p, %s, 0x%08lx)\n", pcs, pcs->handle, debugstr_w(name), addr);
1411
1412 ml.macho_info.flags = MACHO_INFO_MODULE;
1413 ml.ret = FALSE;
1414
1415 if (pcs->dbg_hdr_addr) /* we're debugging a live target */
1416 {
1417 ml.pcs = pcs;
1418 /* do only the lookup from the filename, not the path (as we lookup module
1419 * name in the process' loaded module list)
1420 */
1421 ml.name = strrchrW(name, '/');
1422 if (!ml.name++) ml.name = name;
1423 ml.ret = FALSE;
1424
1425 if (!macho_enum_modules_internal(pcs, NULL, macho_load_cb, &ml))
1426 return NULL;
1427 }
1428 else if (addr)
1429 {
1430 ml.name = name;
1431 ml.ret = macho_search_and_load_file(pcs, ml.name, addr, &ml.macho_info);
1432 }
1433 if (!ml.ret) return NULL;
1434 assert(ml.macho_info.module);
1435 return ml.macho_info.module;
1436 }
1437
1438 #else /* HAVE_MACH_O_LOADER_H */
1439
1440 BOOL macho_synchronize_module_list(struct process* pcs)
1441 {
1442 return FALSE;
1443 }
1444
1445 BOOL macho_fetch_file_info(const WCHAR* name, DWORD_PTR* base,
1446 DWORD* size, DWORD* checksum)
1447 {
1448 return FALSE;
1449 }
1450
1451 BOOL macho_read_wine_loader_dbg_info(struct process* pcs)
1452 {
1453 return FALSE;
1454 }
1455
1456 BOOL macho_enum_modules(HANDLE hProc, enum_modules_cb cb, void* user)
1457 {
1458 return FALSE;
1459 }
1460
1461 struct module* macho_load_module(struct process* pcs, const WCHAR* name, unsigned long addr)
1462 {
1463 return NULL;
1464 }
1465
1466 BOOL macho_load_debug_info(struct module* module, struct macho_file_map* fmap)
1467 {
1468 return FALSE;
1469 }
1470 #endif /* HAVE_MACH_O_LOADER_H */