[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
387 /* If this segment starts before previously-known earliest, record
388 * new earliest. */
389 if (sc->vmaddr < fmap->segs_start)
390 fmap->segs_start = sc->vmaddr;
391
392 /* If this segment extends beyond previously-known furthest, record
393 * new furthest. */
394 tmp = (sc->vmaddr + sc->vmsize + page_mask) & ~page_mask;
395 if (fmap->segs_size < tmp) fmap->segs_size = tmp;
396
397 TRACE("after: 0x%08x - 0x%08x\n", (unsigned)fmap->segs_start, (unsigned)fmap->segs_size);
398
399 return 0;
400 }
401
402 /******************************************************************
403 * macho_map_file
404 *
405 * Maps a Mach-O file into memory (and checks it's a real Mach-O file)
406 */
407 static BOOL macho_map_file(const WCHAR* filenameW, struct macho_file_map* fmap)
408 {
409 struct fat_header fat_header;
410 struct stat statbuf;
411 int i;
412 char* filename;
413 unsigned len;
414 BOOL ret = FALSE;
415
416 TRACE("(%s, %p)\n", debugstr_w(filenameW), fmap);
417
418 fmap->fd = -1;
419 fmap->load_commands = MACHO_NO_MAP;
420 RtlInitializeBitMap(&fmap->sect_is_code, fmap->sect_is_code_buff, MAX_SECT + 1);
421
422 len = WideCharToMultiByte(CP_UNIXCP, 0, filenameW, -1, NULL, 0, NULL, NULL);
423 if (!(filename = HeapAlloc(GetProcessHeap(), 0, len)))
424 {
425 WARN("failed to allocate filename buffer\n");
426 return FALSE;
427 }
428 WideCharToMultiByte(CP_UNIXCP, 0, filenameW, -1, filename, len, NULL, NULL);
429
430 /* check that the file exists */
431 if (stat(filename, &statbuf) == -1 || S_ISDIR(statbuf.st_mode))
432 {
433 TRACE("stat() failed or %s is directory: %s\n", debugstr_a(filename), strerror(errno));
434 goto done;
435 }
436
437 /* Now open the file, so that we can mmap() it. */
438 if ((fmap->fd = open(filename, O_RDONLY)) == -1)
439 {
440 TRACE("failed to open file %s: %d\n", debugstr_a(filename), errno);
441 goto done;
442 }
443
444 if (read(fmap->fd, &fat_header, sizeof(fat_header)) != sizeof(fat_header))
445 {
446 TRACE("failed to read fat header: %d\n", errno);
447 goto done;
448 }
449 TRACE("... got possible fat header\n");
450
451 /* Fat header is always in big-endian order. */
452 if (swap_ulong_be_to_host(fat_header.magic) == FAT_MAGIC)
453 {
454 int narch = swap_ulong_be_to_host(fat_header.nfat_arch);
455 for (i = 0; i < narch; i++)
456 {
457 struct fat_arch fat_arch;
458 if (read(fmap->fd, &fat_arch, sizeof(fat_arch)) != sizeof(fat_arch))
459 goto done;
460 if (swap_ulong_be_to_host(fat_arch.cputype) == CPU_TYPE_X86)
461 {
462 fmap->arch_offset = swap_ulong_be_to_host(fat_arch.offset);
463 fmap->arch_size = swap_ulong_be_to_host(fat_arch.size);
464 break;
465 }
466 }
467 if (i >= narch) goto done;
468 TRACE("... found x86 arch\n");
469 }
470 else
471 {
472 fmap->arch_offset = 0;
473 fmap->arch_size = statbuf.st_size;
474 TRACE("... not a fat header\n");
475 }
476
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))
480 goto done;
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)
487 {
488 case MH_EXECUTE:
489 case MH_DYLIB:
490 case MH_DYLINKER:
491 case MH_BUNDLE:
492 break;
493 default:
494 goto done;
495 }
496 TRACE("... verified Mach x86 header\n");
497
498 fmap->segs_size = 0;
499 fmap->segs_start = ~0L;
500
501 if (macho_enum_load_commands(fmap, LC_SEGMENT, macho_accum_segs_range, NULL) < 0)
502 goto done;
503
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);
507
508 ret = TRUE;
509 done:
510 if (!ret)
511 macho_unmap_file(fmap);
512 HeapFree(GetProcessHeap(), 0, filename);
513 return ret;
514 }
515
516 /******************************************************************
517 * macho_unmap_file
518 *
519 * Unmaps a Mach-O file from memory (previously mapped with macho_map_file)
520 */
521 static void macho_unmap_file(struct macho_file_map* fmap)
522 {
523 TRACE("(%p/%d)\n", fmap, fmap->fd);
524 if (fmap->fd != -1)
525 {
526 macho_unmap_load_commands(fmap);
527 close(fmap->fd);
528 fmap->fd = -1;
529 }
530 }
531
532 /******************************************************************
533 * macho_fill_sect_is_code
534 *
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.
538 */
539 static int macho_fill_sect_is_code(struct macho_file_map* fmap,
540 const struct load_command* lc, void* user)
541 {
542 const struct segment_command* sc = (const struct segment_command*)lc;
543 const struct section* sections;
544 int* cursect = user;
545 int i;
546
547 TRACE("(%p/%d, %p, %p/%d) scanning %u sections\n", fmap, fmap->fd, lc,
548 cursect, *cursect, sc->nsects);
549
550 sections = (const struct section*)(sc + 1);
551 for (i = 0; i < sc->nsects; i++)
552 {
553 if (*cursect > MAX_SECT) return -1;
554 (*cursect)++;
555
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);
559 else
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"));
563 }
564
565 return 0;
566 }
567
568 /******************************************************************
569 * macho_sect_is_code
570 *
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.
574 */
575 static BOOL macho_sect_is_code(struct macho_file_map* fmap, unsigned char sectidx)
576 {
577 TRACE("(%p/%d, %u)\n", fmap, fmap->fd, sectidx);
578
579 if (!RtlAreBitsSet(&fmap->sect_is_code, 0, 1))
580 {
581 int cursect = 0;
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);
585 }
586
587 return RtlAreBitsSet(&fmap->sect_is_code, sectidx, 1);
588 }
589
590 struct symtab_elt
591 {
592 struct hash_table_elt ht_elt;
593 struct symt_compiland* compiland;
594 unsigned long addr;
595 unsigned char is_code:1,
596 is_public:1,
597 is_global:1,
598 used:1;
599 };
600
601 struct macho_debug_info
602 {
603 struct macho_file_map* fmap;
604 struct module* module;
605 struct pool pool;
606 struct hash_table ht_symtab;
607 };
608
609 /******************************************************************
610 * macho_stabs_def_cb
611 *
612 * Callback for stabs_parse. Collect symbol definitions.
613 */
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)
618 {
619 struct macho_debug_info* mdi = user;
620 struct symtab_elt* ste;
621
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);
625
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;
635 ste->used = 0;
636 hash_table_add(&mdi->ht_symtab, &ste->ht_elt);
637 }
638
639 /******************************************************************
640 * macho_parse_symtab
641 *
642 * Callback for macho_enum_load_commands. Processes the LC_SYMTAB
643 * load commands from the Mach-O file.
644 */
645 static int macho_parse_symtab(struct macho_file_map* fmap,
646 const struct load_command* lc, void* user)
647 {
648 const struct symtab_command* sc = (const struct symtab_command*)lc;
649 struct macho_debug_info* mdi = user;
650 const struct nlist* stab;
651 const char* stabstr;
652 int ret = 0;
653
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);
656
657 if (!macho_map_ranges(fmap, sc->symoff, sc->nsyms * sizeof(struct nlist),
658 sc->stroff, sc->strsize, (const void**)&stab, (const void**)&stabstr))
659 return 0;
660
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))
665 ret = -1;
666
667 macho_unmap_ranges(fmap, sc->symoff, sc->nsyms * sizeof(struct nlist),
668 sc->stroff, sc->strsize, (const void**)&stab, (const void**)&stabstr);
669
670 return ret;
671 }
672
673 /******************************************************************
674 * macho_finish_stabs
675 *
676 * Integrate the non-debugging symbols we've gathered into the
677 * symbols that were generated during stabs parsing.
678 */
679 static void macho_finish_stabs(struct module* module, struct hash_table* ht_symtab)
680 {
681 struct hash_table_iter hti_ours;
682 struct symtab_elt* ste;
683 BOOL adjusted = FALSE;
684
685 TRACE("(%p, %p)\n", module, ht_symtab);
686
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)))
691 {
692 struct hash_table_iter hti_modules;
693 void* ptr;
694 struct symt_ht* sym;
695 struct symt_function* func;
696 struct symt_data* data;
697
698 hash_table_iter_init(&module->ht_symbols, &hti_modules, ste->ht_elt.name);
699 while ((ptr = hash_table_iter_up(&hti_modules)))
700 {
701 sym = GET_ENTRY(ptr, struct symt_ht, hash_elt);
702
703 if (strcmp(sym->hash_elt.name, ste->ht_elt.name))
704 continue;
705
706 switch (sym->symt.tag)
707 {
708 case SymTagFunction:
709 func = (struct symt_function*)sym;
710 if (func->address == module->format_info[DFI_MACHO]->u.macho_info->load_addr)
711 {
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;
716 adjusted = TRUE;
717 }
718 if (func->address == ste->addr)
719 ste->used = 1;
720 break;
721 case SymTagData:
722 data = (struct symt_data*)sym;
723 switch (data->kind)
724 {
725 case DataIsGlobal:
726 case DataIsFileStatic:
727 if (data->u.var.offset == module->format_info[DFI_MACHO]->u.macho_info->load_addr)
728 {
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;
733 adjusted = TRUE;
734 }
735 if (data->u.var.offset == ste->addr)
736 {
737 enum DataKind new_kind;
738
739 new_kind = ste->is_global ? DataIsGlobal : DataIsFileStatic;
740 if (data->kind != new_kind)
741 {
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;
746 adjusted = TRUE;
747 }
748 ste->used = 1;
749 }
750 break;
751 default:;
752 }
753 break;
754 default:
755 TRACE("Ignoring tag %u\n", sym->symt.tag);
756 break;
757 }
758 }
759 }
760
761 if (adjusted)
762 {
763 /* since we may have changed some addresses, mark the module to be resorted */
764 module->sortlist_valid = FALSE;
765 }
766
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))
773 {
774 hash_table_iter_init(ht_symtab, &hti_ours, NULL);
775 while ((ste = hash_table_iter_up(&hti_ours)))
776 {
777 struct symt_ht* sym;
778 ULONG64 addr;
779
780 if (ste->used) continue;
781
782 sym = symt_find_nearest(module, ste->addr);
783 if (sym)
784 symt_get_address(&sym->symt, &addr);
785 if (sym && ste->addr == addr)
786 {
787 ULONG64 size = 0;
788 DWORD kind = -1;
789
790 ste->used = 1;
791
792 /* If neither symbol has a correct size (ours never does), we
793 * consider them both to be markers. No warning is needed in
794 * that case.
795 * Also, we check that we don't have two symbols, one local, the other
796 * global, which is legal.
797 */
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,
804 sym->hash_elt.name,
805 wine_dbgstr_longlong(addr), wine_dbgstr_longlong(size));
806 }
807 }
808 }
809
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)))
814 {
815 if (!(dbghelp_options & SYMOPT_PUBLICS_ONLY) && !ste->used)
816 {
817 if (ste->is_code)
818 {
819 symt_new_function(module, ste->compiland, ste->ht_elt.name,
820 ste->addr, 0, NULL);
821 }
822 else
823 {
824 struct location loc;
825
826 loc.kind = loc_absolute;
827 loc.reg = 0;
828 loc.offset = ste->addr;
829 symt_new_global_variable(module, ste->compiland, ste->ht_elt.name,
830 !ste->is_global, loc, 0, NULL);
831 }
832
833 ste->used = 1;
834 }
835
836 if (ste->is_public && !(dbghelp_options & SYMOPT_NO_PUBLICS))
837 {
838 symt_new_public(module, ste->compiland, ste->ht_elt.name, ste->addr, 0);
839 }
840 }
841 }
842
843 /******************************************************************
844 * macho_load_debug_info_from_map
845 *
846 * Loads the symbolic information from a Mach-O module.
847 * Returns
848 * FALSE if the file doesn't contain symbolic info (or this info
849 * cannot be read or parsed)
850 * TRUE on success
851 */
852 static BOOL macho_load_debug_info_from_map(struct module* module,
853 struct macho_file_map* fmap)
854 {
855 BOOL ret = FALSE;
856 struct macho_debug_info mdi;
857 int result;
858
859 TRACE("(%p, %p/%d)\n", module, fmap, fmap->fd);
860
861 module->module.SymType = SymExport;
862
863 mdi.fmap = fmap;
864 mdi.module = module;
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);
868 if (result > 0)
869 ret = TRUE;
870 else if (result < 0)
871 WARN("Couldn't correctly read stabs\n");
872
873 macho_finish_stabs(module, &mdi.ht_symtab);
874
875 pool_destroy(&mdi.pool);
876 return ret;
877 }
878
879 /******************************************************************
880 * macho_load_debug_info
881 *
882 * Loads Mach-O debugging information from the module image file.
883 */
884 BOOL macho_load_debug_info(struct module* module, struct macho_file_map* fmap)
885 {
886 BOOL ret = TRUE;
887 struct macho_file_map my_fmap;
888
889 TRACE("(%p, %p/%d)\n", module, fmap, fmap ? fmap->fd : -1);
890
891 if (module->type != DMT_MACHO || !module->format_info[DFI_MACHO]->u.macho_info)
892 {
893 ERR("Bad Mach-O module '%s'\n", debugstr_w(module->module.LoadedImageName));
894 return FALSE;
895 }
896
897 if (!fmap)
898 {
899 fmap = &my_fmap;
900 ret = macho_map_file(module->module.LoadedImageName, fmap);
901 }
902 if (ret)
903 ret = macho_load_debug_info_from_map(module, fmap);
904
905 if (fmap == &my_fmap) macho_unmap_file(fmap);
906 return ret;
907 }
908
909 /******************************************************************
910 * macho_fetch_file_info
911 *
912 * Gathers some more information for a Mach-O module from a given file
913 */
914 BOOL macho_fetch_file_info(const WCHAR* name, DWORD_PTR* base,
915 DWORD* size, DWORD* checksum)
916 {
917 struct macho_file_map fmap;
918
919 TRACE("(%s, %p, %p, %p)\n", debugstr_w(name), base, size, checksum);
920
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);
926 return TRUE;
927 }
928
929 /******************************************************************
930 * macho_load_file
931 *
932 * Loads the information for Mach-O module stored in 'filename'.
933 * The module has been loaded at 'load_addr' address.
934 * returns
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)
937 * TRUE on success
938 */
939 static BOOL macho_load_file(struct process* pcs, const WCHAR* filename,
940 unsigned long load_addr, struct macho_info* macho_info)
941 {
942 BOOL ret = TRUE;
943 struct macho_file_map fmap;
944
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);
947
948 if (!macho_map_file(filename, &fmap)) return FALSE;
949
950 /* Find the dynamic loader's table of images loaded into the process.
951 */
952 if (macho_info->flags & MACHO_INFO_DEBUG_HEADER)
953 {
954 PROCESS_BASIC_INFORMATION pbi;
955 NTSTATUS status;
956
957 ret = FALSE;
958
959 /* Get address of PEB */
960 status = NtQueryInformationProcess(pcs->handle, ProcessBasicInformation,
961 &pbi, sizeof(pbi), NULL);
962 if (status == STATUS_SUCCESS)
963 {
964 ULONG dyld_image_info;
965
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))
969 {
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;
973 ret = TRUE;
974 }
975 }
976
977 if (!ret)
978 {
979 static void* dyld_all_image_infos_addr;
980
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)
984 {
985 struct nlist nl[2];
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;
990 }
991
992 if (dyld_all_image_infos_addr)
993 {
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;
997 ret = TRUE;
998 }
999 }
1000 }
1001
1002 if (macho_info->flags & MACHO_INFO_MODULE)
1003 {
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)
1011 {
1012 HeapFree(GetProcessHeap(), 0, modfmt);
1013 goto leave;
1014 }
1015 macho_module_info = (void*)(modfmt + 1);
1016 macho_info->module->format_info[DFI_MACHO] = modfmt;
1017
1018 modfmt->module = macho_info->module;
1019 modfmt->remove = NULL;
1020 modfmt->loc_compute = NULL;
1021 modfmt->u.macho_info = macho_module_info;
1022
1023 macho_module_info->load_addr = load_addr;
1024
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))
1028 ret = FALSE;
1029
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);
1033 }
1034
1035 if (macho_info->flags & MACHO_INFO_NAME)
1036 {
1037 WCHAR* ptr;
1038 ptr = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(filename) + 1) * sizeof(WCHAR));
1039 if (ptr)
1040 {
1041 strcpyW(ptr, filename);
1042 macho_info->module_name = ptr;
1043 }
1044 else ret = FALSE;
1045 TRACE("module_name = %p %s\n", macho_info->module_name, debugstr_w(macho_info->module_name));
1046 }
1047 leave:
1048 macho_unmap_file(&fmap);
1049
1050 TRACE(" => %d\n", ret);
1051 return ret;
1052 }
1053
1054 /******************************************************************
1055 * macho_load_file_from_path
1056 * Tries to load a Mach-O file from a set of paths (separated by ':')
1057 */
1058 static BOOL macho_load_file_from_path(struct process* pcs,
1059 const WCHAR* filename,
1060 unsigned long load_addr,
1061 const char* path,
1062 struct macho_info* macho_info)
1063 {
1064 BOOL ret = FALSE;
1065 WCHAR *s, *t, *fn;
1066 WCHAR* pathW = NULL;
1067 unsigned len;
1068
1069 TRACE("(%p/%p, %s, 0x%08lx, %s, %p)\n", pcs, pcs->handle, debugstr_w(filename), load_addr,
1070 debugstr_a(path), macho_info);
1071
1072 if (!path) return FALSE;
1073
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);
1078
1079 for (s = pathW; s && *s; s = (t) ? (t+1) : NULL)
1080 {
1081 t = strchrW(s, ':');
1082 if (t) *t = '\0';
1083 fn = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(filename) + 1 + lstrlenW(s) + 1) * sizeof(WCHAR));
1084 if (!fn) break;
1085 strcpyW(fn, s);
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);
1090 if (ret) break;
1091 s = (t) ? (t+1) : NULL;
1092 }
1093
1094 TRACE(" => %d\n", ret);
1095 HeapFree(GetProcessHeap(), 0, pathW);
1096 return ret;
1097 }
1098
1099 /******************************************************************
1100 * macho_load_file_from_dll_path
1101 *
1102 * Tries to load a Mach-O file from the dll path
1103 */
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)
1108 {
1109 BOOL ret = FALSE;
1110 unsigned int index = 0;
1111 const char *path;
1112
1113 TRACE("(%p/%p, %s, 0x%08lx, %p)\n", pcs, pcs->handle, debugstr_w(filename), load_addr,
1114 macho_info);
1115
1116 while (!ret && (path = wine_dll_enum_load_path( index++ )))
1117 {
1118 WCHAR *name;
1119 unsigned len;
1120
1121 len = MultiByteToWideChar(CP_UNIXCP, 0, path, -1, NULL, 0);
1122
1123 name = HeapAlloc( GetProcessHeap(), 0,
1124 (len + lstrlenW(filename) + 2) * sizeof(WCHAR) );
1125
1126 if (!name) break;
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 );
1132 }
1133 TRACE(" => %d\n", ret);
1134 return ret;
1135 }
1136
1137 /******************************************************************
1138 * macho_search_and_load_file
1139 *
1140 * Lookup a file in standard Mach-O locations, and if found, load it
1141 */
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)
1145 {
1146 BOOL ret = FALSE;
1147 struct module* module;
1148 static const WCHAR S_libstdcPPW[] = {'l','i','b','s','t','d','c','+','+','\0'};
1149 const WCHAR* p;
1150
1151 TRACE("(%p/%p, %s, 0x%08lx, %p)\n", pcs, pcs->handle, debugstr_w(filename), load_addr,
1152 macho_info);
1153
1154 if (filename == NULL || *filename == '\0') return FALSE;
1155 if ((module = module_is_already_loaded(pcs, filename)))
1156 {
1157 macho_info->module = module;
1158 module->format_info[DFI_MACHO]->u.macho_info->in_use = 1;
1159 return module->module.SymType;
1160 }
1161
1162 if (strstrW(filename, S_libstdcPPW)) return FALSE; /* We know we can't do it */
1163
1164 /* If has no directories, try LD_LIBRARY_PATH first. */
1165 if (!strchrW(filename, '/'))
1166 {
1167 ret = macho_load_file_from_path(pcs, filename, load_addr,
1168 getenv("PATH"), macho_info);
1169 }
1170 /* Try DYLD_LIBRARY_PATH, with just the filename (no directories). */
1171 if (!ret)
1172 {
1173 if ((p = strrchrW(filename, '/'))) p++;
1174 else p = filename;
1175 ret = macho_load_file_from_path(pcs, p, load_addr,
1176 getenv("DYLD_LIBRARY_PATH"), macho_info);
1177 }
1178 /* Try the path as given. */
1179 if (!ret)
1180 ret = macho_load_file(pcs, filename, load_addr, macho_info);
1181 /* Try DYLD_FALLBACK_LIBRARY_PATH, with just the filename (no directories). */
1182 if (!ret)
1183 {
1184 ret = macho_load_file_from_path(pcs, p, load_addr,
1185 getenv("DYLD_FALLBACK_LIBRARY_PATH"), macho_info);
1186 }
1187 if (!ret && !strchrW(filename, '/'))
1188 ret = macho_load_file_from_dll_path(pcs, filename, load_addr, macho_info);
1189
1190 return ret;
1191 }
1192
1193 /******************************************************************
1194 * macho_enum_modules_internal
1195 *
1196 * Enumerate Mach-O modules from a running process
1197 */
1198 static BOOL macho_enum_modules_internal(const struct process* pcs,
1199 const WCHAR* main_name,
1200 enum_modules_cb cb, void* user)
1201 {
1202 struct dyld_all_image_infos image_infos;
1203 struct dyld_image_info* info_array = NULL;
1204 unsigned long len;
1205 int i;
1206 char bufstr[256];
1207 WCHAR bufstrW[MAX_PATH];
1208 BOOL ret = FALSE;
1209
1210 TRACE("(%p/%p, %s, %p, %p)\n", pcs, pcs->handle, debugstr_w(main_name), cb,
1211 user);
1212
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)
1217 goto done;
1218 TRACE("Process has %u image infos at %p\n", image_infos.infoArrayCount, image_infos.infoArray);
1219
1220 len = image_infos.infoArrayCount * sizeof(info_array[0]);
1221 info_array = HeapAlloc(GetProcessHeap(), 0, len);
1222 if (!info_array ||
1223 !ReadProcessMemory(pcs->handle, image_infos.infoArray,
1224 info_array, len, NULL))
1225 goto done;
1226 TRACE("... read image infos\n");
1227
1228 for (i = 0; i < image_infos.infoArrayCount; i++)
1229 {
1230 if (info_array[i].imageFilePath != NULL &&
1231 ReadProcessMemory(pcs->handle, info_array[i].imageFilePath, bufstr, sizeof(bufstr), NULL))
1232 {
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;
1238 }
1239 }
1240
1241 ret = TRUE;
1242 done:
1243 HeapFree(GetProcessHeap(), 0, info_array);
1244 return ret;
1245 }
1246
1247 struct macho_sync
1248 {
1249 struct process* pcs;
1250 struct macho_info macho_info;
1251 };
1252
1253 static BOOL macho_enum_sync_cb(const WCHAR* name, unsigned long addr, void* user)
1254 {
1255 struct macho_sync* ms = user;
1256
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);
1259 return TRUE;
1260 }
1261
1262 /******************************************************************
1263 * macho_synchronize_module_list
1264 *
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
1269 */
1270 BOOL macho_synchronize_module_list(struct process* pcs)
1271 {
1272 struct module* module;
1273 struct macho_sync ms;
1274
1275 TRACE("(%p/%p)\n", pcs, pcs->handle);
1276
1277 for (module = pcs->lmodules; module; module = module->next)
1278 {
1279 if (module->type == DMT_MACHO && !module->is_virtual)
1280 module->format_info[DFI_MACHO]->u.macho_info->in_use = 0;
1281 }
1282
1283 ms.pcs = pcs;
1284 ms.macho_info.flags = MACHO_INFO_MODULE;
1285 if (!macho_enum_modules_internal(pcs, NULL, macho_enum_sync_cb, &ms))
1286 return FALSE;
1287
1288 module = pcs->lmodules;
1289 while (module)
1290 {
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)
1294 {
1295 module_remove(pcs, module);
1296 /* restart all over */
1297 module = pcs->lmodules;
1298 }
1299 else module = module->next;
1300 }
1301 return TRUE;
1302 }
1303
1304 /******************************************************************
1305 * macho_search_loader
1306 *
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.
1311 */
1312 static BOOL macho_search_loader(struct process* pcs, struct macho_info* macho_info)
1313 {
1314 return macho_search_and_load_file(pcs, get_wine_loader_name(), 0, macho_info);
1315 }
1316
1317 /******************************************************************
1318 * macho_read_wine_loader_dbg_info
1319 *
1320 * Try to find a decent wine executable which could have loaded the debuggee
1321 */
1322 BOOL macho_read_wine_loader_dbg_info(struct process* pcs)
1323 {
1324 struct macho_info macho_info;
1325
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;
1332 }
1333
1334 /******************************************************************
1335 * macho_enum_modules
1336 *
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.
1340 */
1341 BOOL macho_enum_modules(HANDLE hProc, enum_modules_cb cb, void* user)
1342 {
1343 struct process pcs;
1344 struct macho_info macho_info;
1345 BOOL ret;
1346
1347 TRACE("(%p, %p, %p)\n", hProc, cb, user);
1348 memset(&pcs, 0, sizeof(pcs));
1349 pcs.handle = hProc;
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);
1355 return ret;
1356 }
1357
1358 struct macho_load
1359 {
1360 struct process* pcs;
1361 struct macho_info macho_info;
1362 const WCHAR* name;
1363 BOOL ret;
1364 };
1365
1366 /******************************************************************
1367 * macho_load_cb
1368 *
1369 * Callback for macho_load_module, used to walk the list of loaded
1370 * modules.
1371 */
1372 static BOOL macho_load_cb(const WCHAR* name, unsigned long addr, void* user)
1373 {
1374 struct macho_load* ml = user;
1375 const WCHAR* p;
1376
1377 TRACE("(%s, 0x%08lx, %p)\n", debugstr_w(name), addr, user);
1378
1379 /* memcmp is needed for matches when bufstr contains also version information
1380 * ml->name: libc.so, name: libc.so.6.0
1381 */
1382 p = strrchrW(name, '/');
1383 if (!p++) p = name;
1384 if (!memcmp(p, ml->name, lstrlenW(ml->name) * sizeof(WCHAR)))
1385 {
1386 ml->ret = macho_search_and_load_file(ml->pcs, name, addr, &ml->macho_info);
1387 return FALSE;
1388 }
1389 return TRUE;
1390 }
1391
1392 /******************************************************************
1393 * macho_load_module
1394 *
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.
1398 */
1399 struct module* macho_load_module(struct process* pcs, const WCHAR* name, unsigned long addr)
1400 {
1401 struct macho_load ml;
1402
1403 TRACE("(%p/%p, %s, 0x%08lx)\n", pcs, pcs->handle, debugstr_w(name), addr);
1404
1405 ml.macho_info.flags = MACHO_INFO_MODULE;
1406 ml.ret = FALSE;
1407
1408 if (pcs->dbg_hdr_addr) /* we're debugging a live target */
1409 {
1410 ml.pcs = pcs;
1411 /* do only the lookup from the filename, not the path (as we lookup module
1412 * name in the process' loaded module list)
1413 */
1414 ml.name = strrchrW(name, '/');
1415 if (!ml.name++) ml.name = name;
1416 ml.ret = FALSE;
1417
1418 if (!macho_enum_modules_internal(pcs, NULL, macho_load_cb, &ml))
1419 return NULL;
1420 }
1421 else if (addr)
1422 {
1423 ml.name = name;
1424 ml.ret = macho_search_and_load_file(pcs, ml.name, addr, &ml.macho_info);
1425 }
1426 if (!ml.ret) return NULL;
1427 assert(ml.macho_info.module);
1428 return ml.macho_info.module;
1429 }
1430
1431 #else /* HAVE_MACH_O_LOADER_H */
1432
1433 BOOL macho_synchronize_module_list(struct process* pcs)
1434 {
1435 return FALSE;
1436 }
1437
1438 BOOL macho_fetch_file_info(const WCHAR* name, DWORD_PTR* base,
1439 DWORD* size, DWORD* checksum)
1440 {
1441 return FALSE;
1442 }
1443
1444 BOOL macho_read_wine_loader_dbg_info(struct process* pcs)
1445 {
1446 return FALSE;
1447 }
1448
1449 BOOL macho_enum_modules(HANDLE hProc, enum_modules_cb cb, void* user)
1450 {
1451 return FALSE;
1452 }
1453
1454 struct module* macho_load_module(struct process* pcs, const WCHAR* name, unsigned long addr)
1455 {
1456 return NULL;
1457 }
1458
1459 BOOL macho_load_debug_info(struct module* module, struct macho_file_map* fmap)
1460 {
1461 return FALSE;
1462 }
1463 #endif /* HAVE_MACH_O_LOADER_H */