ReactOS 0.4.16-dev-319-g6cf4263
macho_module.c
Go to the documentation of this file.
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 <stdio.h>
25#include <assert.h>
26#include <stdarg.h>
27#include <errno.h>
28
29#include "ntstatus.h"
30#define WIN32_NO_STATUS
31#include "dbghelp_private.h"
32#include "image_private.h"
33
34#include "winternl.h"
35#include "winioctl.h"
36#define WINE_MOUNTMGR_EXTENSIONS
37#include "ddk/mountmgr.h"
38
39#include "wine/debug.h"
40#include "wine/heap.h"
41
43{
44 UINT32 imageLoadAddress; /* const struct mach_header* */
45 UINT32 imageFilePath; /* const char* */
46 UINT32 imageFileModDate; /* uintptr_t */
47};
48
50{
53 UINT32 infoArray; /* const struct dyld_image_info* */
54};
55
57{
58 UINT64 imageLoadAddress; /* const struct mach_header* */
59 UINT64 imageFilePath; /* const char* */
60 UINT64 imageFileModDate; /* uintptr_t */
61};
62
64{
67 UINT64 infoArray; /* const struct dyld_image_info* */
68};
69
73};
74
78};
79
81{
82 UINT32 magic; /* mach magic number identifier */
83 UINT32 cputype; /* cpu specifier */
84 UINT32 cpusubtype; /* machine specifier */
85 UINT32 filetype; /* type of file */
86 UINT32 ncmds; /* number of load commands */
87 UINT32 sizeofcmds; /* the size of all the load commands */
88 UINT32 flags; /* flags */
89 UINT32 reserved; /* reserved */
90};
91
93{
94 UINT32 cmd; /* LC_SEGMENT_64 */
95 UINT32 cmdsize; /* includes sizeof section_64 structs */
96 char segname[16]; /* segment name */
97 UINT64 vmaddr; /* memory address of this segment */
98 UINT64 vmsize; /* memory size of this segment */
99 UINT64 fileoff; /* file offset of this segment */
100 UINT64 filesize; /* amount to map from the file */
101 UINT32 maxprot; /* maximum VM protection */
102 UINT32 initprot; /* initial VM protection */
103 UINT32 nsects; /* number of sections in segment */
104 UINT32 flags; /* flags */
105};
106
108{
109 UINT32 cmd; /* LC_SEGMENT */
110 UINT32 cmdsize; /* includes sizeof section structs */
111 char segname[16]; /* segment name */
112 UINT32 vmaddr; /* memory address of this segment */
113 UINT32 vmsize; /* memory size of this segment */
114 UINT32 fileoff; /* file offset of this segment */
115 UINT32 filesize; /* amount to map from the file */
116 UINT32 maxprot; /* maximum VM protection */
117 UINT32 initprot; /* initial VM protection */
118 UINT32 nsects; /* number of sections in segment */
119 UINT32 flags; /* flags */
120};
121
123{
124 UINT32 cmd; /* LC_SYMTAB */
125 UINT32 cmdsize; /* sizeof(struct symtab_command) */
126 UINT32 symoff; /* symbol table offset */
127 UINT32 nsyms; /* number of symbol table entries */
128 UINT32 stroff; /* string table offset */
129 UINT32 strsize; /* string table size in bytes */
130};
131
132#ifdef WORDS_BIGENDIAN
133#define swap_ulong_be_to_host(n) (n)
134#else
135#define swap_ulong_be_to_host(n) (RtlUlongByteSwap(n))
136#endif
137
139
140
141/* Bitmask for Mach-O image header flags indicating that the image is in dyld's
142 shared cached. That implies that its segments are mapped non-contiguously.
143 This value isn't defined anywhere in headers. It's used in dyld and in
144 debuggers which support OS X as a magic number.
145
146 The flag also isn't set in the on-disk image file. It's only set in
147 memory by dyld. */
148#define MACHO_DYLD_IN_SHARED_CACHE 0x80000000
149
150#define MACHO_FAT_MAGIC 0xcafebabe
151#define MACHO_MH_MAGIC_32 0xfeedface
152#define MACHO_MH_MAGIC_64 0xfeedfacf
153
154#define MACHO_CPU_TYPE_X86 0x00000007
155#define MACHO_CPU_TYPE_X86_64 0x01000007
156
157#define MACHO_MH_EXECUTE 0x2
158#define MACHO_MH_DYLIB 0x6
159#define MACHO_MH_DYLINKER 0x7
160#define MACHO_MH_BUNDLE 0x8
161#define MACHO_MH_DSYM 0xa
162
163#define MACHO_LC_SEGMENT 0x01
164#define MACHO_LC_SYMTAB 0x02
165#define MACHO_LC_SEGMENT_64 0x19
166#define MACHO_LC_UUID 0x1b
167
168#define MACHO_SECTION_TYPE 0x000000ff
169#define MACHO_S_ATTR_PURE_INSTRUCTIONS 0x80000000
170#define MACHO_S_ATTR_SOME_INSTRUCTIONS 0x00000400
171
172#define UUID_STRING_LEN 37 /* 16 bytes at 2 hex digits apiece, 4 dashes, and the null terminator */
173
174
176{
179 unsigned short in_use : 1,
181};
182
184{
186 unsigned int section_index;
187};
188
189#define MACHO_INFO_MODULE 0x0001
190#define MACHO_INFO_NAME 0x0002
191
193{
194 unsigned flags; /* IN one (or several) of the MACHO_INFO constants */
195 struct module* module; /* OUT loaded module (if MACHO_INFO_MODULE is set) */
196 const WCHAR* module_name; /* OUT found module name (if MACHO_INFO_NAME is set) */
197};
198
199static void macho_unmap_file(struct image_file_map* fmap);
200
201static char* format_uuid(const UINT8 uuid[16], char out[UUID_STRING_LEN])
202{
203 sprintf(out, "%02X%02X%02X%02X-%02X%02X-%02X%02X-%02X%02X-%02X%02X%02X%02X%02X%02X",
204 uuid[0], uuid[1], uuid[2], uuid[3], uuid[4], uuid[5], uuid[6], uuid[7],
205 uuid[8], uuid[9], uuid[10], uuid[11], uuid[12], uuid[13], uuid[14], uuid[15]);
206 return out;
207}
208
209/******************************************************************
210 * macho_calc_range
211 *
212 * For a range (offset & length) of a single architecture within
213 * a Mach-O file, calculate the page-aligned range of the whole file
214 * that encompasses it. For a fat binary, the architecture will
215 * itself be offset within the file, so take that into account.
216 */
217static void macho_calc_range(const struct macho_file_map* fmap, ULONG_PTR offset,
218 ULONG_PTR len, ULONG_PTR* out_aligned_offset,
219 ULONG_PTR* out_aligned_end, ULONG_PTR* out_misalign)
220{
221 ULONG_PTR pagemask;
222 ULONG_PTR file_offset, misalign;
223
224 pagemask = sysinfo.dwAllocationGranularity - 1;
225 file_offset = fmap->arch_offset + offset;
226 misalign = file_offset & pagemask;
227 *out_aligned_offset = file_offset - misalign;
228 *out_aligned_end = file_offset + len;
229 if (out_misalign)
230 *out_misalign = misalign;
231}
232
233/******************************************************************
234 * macho_map_range
235 *
236 * Maps a range (offset, length in bytes) from a Mach-O file into memory
237 */
238static const char* macho_map_range(const struct macho_file_map* fmap, ULONG_PTR offset, ULONG_PTR len,
239 const char** base)
240{
241 ULONG_PTR misalign, aligned_offset, aligned_map_end;
242 const void* aligned_ptr;
244
245 TRACE("(%p/%p, 0x%08lx, 0x%08lx)\n", fmap, fmap->handle, offset, len);
246
247 macho_calc_range(fmap, offset, len, &aligned_offset, &aligned_map_end, &misalign);
248
249 if (!(mapping = CreateFileMappingW(fmap->handle, NULL, PAGE_READONLY, 0, 0, NULL)))
250 {
251 ERR("map creation %p failed %u size %lu\n", fmap->handle, GetLastError(), aligned_map_end);
252 return IMAGE_NO_MAP;
253 }
254 aligned_ptr = MapViewOfFile(mapping, FILE_MAP_READ, 0, aligned_offset, aligned_map_end - aligned_offset);
256 if (!aligned_ptr)
257 {
258 ERR("map failed %u\n", GetLastError());
259 return IMAGE_NO_MAP;
260 }
261
262 TRACE("Mapped (0x%08lx - 0x%08lx) to %p\n", aligned_offset, aligned_map_end, aligned_ptr);
263
264 if (base)
265 *base = aligned_ptr;
266 return (const char*)aligned_ptr + misalign;
267}
268
269/******************************************************************
270 * macho_unmap_range
271 *
272 * Unmaps a range (offset, length in bytes) of a Mach-O file from memory
273 */
274static void macho_unmap_range(const char** base, const void** mapped, const struct macho_file_map* fmap,
276{
277 TRACE("(%p, %p, %p/%p, 0x%08lx, 0x%08lx)\n", base, mapped, fmap, fmap->handle, offset, len);
278
279 if ((mapped && *mapped != IMAGE_NO_MAP) || (base && *base != IMAGE_NO_MAP))
280 {
281 ULONG_PTR misalign, aligned_offset, aligned_map_end;
282 void* aligned_ptr;
283
284 macho_calc_range(fmap, offset, len, &aligned_offset, &aligned_map_end, &misalign);
285
286 if (mapped)
287 aligned_ptr = (char*)*mapped - misalign;
288 else
289 aligned_ptr = (void*)*base;
290 if (!UnmapViewOfFile(aligned_ptr))
291 WARN("Couldn't unmap the range\n");
292 if (mapped)
293 *mapped = IMAGE_NO_MAP;
294 if (base)
296 }
297}
298
299/******************************************************************
300 * macho_map_ranges
301 *
302 * Maps two ranges (offset, length in bytes) from a Mach-O file
303 * into memory. If the two ranges overlap, use one mmap so that
304 * the munmap doesn't fragment the mapping.
305 */
306static BOOL macho_map_ranges(const struct macho_file_map* fmap,
307 ULONG_PTR offset1, ULONG_PTR len1,
308 ULONG_PTR offset2, ULONG_PTR len2,
309 const void** mapped1, const void** mapped2)
310{
311 ULONG_PTR aligned_offset1, aligned_map_end1;
312 ULONG_PTR aligned_offset2, aligned_map_end2;
313
314 TRACE("(%p/%p, 0x%08lx, 0x%08lx, 0x%08lx, 0x%08lx, %p, %p)\n", fmap, fmap->handle,
315 offset1, len1, offset2, len2, mapped1, mapped2);
316
317 macho_calc_range(fmap, offset1, len1, &aligned_offset1, &aligned_map_end1, NULL);
318 macho_calc_range(fmap, offset2, len2, &aligned_offset2, &aligned_map_end2, NULL);
319
320 if (aligned_map_end1 < aligned_offset2 || aligned_map_end2 < aligned_offset1)
321 {
322 *mapped1 = macho_map_range(fmap, offset1, len1, NULL);
323 if (*mapped1 != IMAGE_NO_MAP)
324 {
325 *mapped2 = macho_map_range(fmap, offset2, len2, NULL);
326 if (*mapped2 == IMAGE_NO_MAP)
327 macho_unmap_range(NULL, mapped1, fmap, offset1, len1);
328 }
329 }
330 else
331 {
332 if (offset1 < offset2)
333 {
334 *mapped1 = macho_map_range(fmap, offset1, offset2 + len2 - offset1, NULL);
335 if (*mapped1 != IMAGE_NO_MAP)
336 *mapped2 = (const char*)*mapped1 + offset2 - offset1;
337 }
338 else
339 {
340 *mapped2 = macho_map_range(fmap, offset2, offset1 + len1 - offset2, NULL);
341 if (*mapped2 != IMAGE_NO_MAP)
342 *mapped1 = (const char*)*mapped2 + offset1 - offset2;
343 }
344 }
345
346 TRACE(" => %p, %p\n", *mapped1, *mapped2);
347
348 return (*mapped1 != IMAGE_NO_MAP) && (*mapped2 != IMAGE_NO_MAP);
349}
350
351/******************************************************************
352 * macho_unmap_ranges
353 *
354 * Unmaps two ranges (offset, length in bytes) of a Mach-O file
355 * from memory. Use for ranges which were mapped by
356 * macho_map_ranges.
357 */
358static void macho_unmap_ranges(const struct macho_file_map* fmap,
359 ULONG_PTR offset1, ULONG_PTR len1,
360 ULONG_PTR offset2, ULONG_PTR len2,
361 const void** mapped1, const void** mapped2)
362{
363 ULONG_PTR aligned_offset1, aligned_map_end1;
364 ULONG_PTR aligned_offset2, aligned_map_end2;
365
366 TRACE("(%p/%p, 0x%08lx, 0x%08lx, 0x%08lx, 0x%08lx, %p/%p, %p/%p)\n", fmap, fmap->handle,
367 offset1, len1, offset2, len2, mapped1, *mapped1, mapped2, *mapped2);
368
369 macho_calc_range(fmap, offset1, len1, &aligned_offset1, &aligned_map_end1, NULL);
370 macho_calc_range(fmap, offset2, len2, &aligned_offset2, &aligned_map_end2, NULL);
371
372 if (aligned_map_end1 < aligned_offset2 || aligned_map_end2 < aligned_offset1)
373 {
374 macho_unmap_range(NULL, mapped1, fmap, offset1, len1);
375 macho_unmap_range(NULL, mapped2, fmap, offset2, len2);
376 }
377 else
378 {
379 if (offset1 < offset2)
380 {
381 macho_unmap_range(NULL, mapped1, fmap, offset1, offset2 + len2 - offset1);
382 *mapped2 = IMAGE_NO_MAP;
383 }
384 else
385 {
386 macho_unmap_range(NULL, mapped2, fmap, offset2, offset1 + len1 - offset2);
387 *mapped1 = IMAGE_NO_MAP;
388 }
389 }
390}
391
392/******************************************************************
393 * macho_find_section
394 */
395static BOOL macho_find_segment_section(struct image_file_map* ifm, const char* segname, const char* sectname, struct image_section_map* ism)
396{
397 struct macho_file_map* fmap;
398 unsigned i;
399 char tmp[sizeof(fmap->sect[0].section.sectname)];
400
401 /* Other parts of dbghelp use section names like ".eh_frame". Mach-O uses
402 names like "__eh_frame". Convert those. */
403 if (sectname[0] == '.')
404 {
405 lstrcpynA(tmp, "__", sizeof(tmp));
406 lstrcpynA(tmp + 2, sectname + 1, sizeof(tmp) - 2);
407 sectname = tmp;
408 }
409
410 while (ifm)
411 {
412 fmap = &ifm->u.macho;
413 for (i = 0; i < fmap->num_sections; i++)
414 {
415 if (!fmap->sect[i].ignored &&
416 strcmp(fmap->sect[i].section.sectname, sectname) == 0 &&
417 (!segname || strcmp(fmap->sect[i].section.segname, segname) == 0))
418 {
419 ism->fmap = ifm;
420 ism->sidx = i;
421 return TRUE;
422 }
423 }
424 ifm = fmap->dsym;
425 }
426
427 ism->fmap = NULL;
428 ism->sidx = -1;
429 return FALSE;
430}
431
432static BOOL macho_find_section(struct image_file_map* ifm, const char* sectname, struct image_section_map* ism)
433{
434 return macho_find_segment_section(ifm, NULL, sectname, ism);
435}
436
437/******************************************************************
438 * macho_map_section
439 */
440const char* macho_map_section(struct image_section_map* ism)
441{
442 struct macho_file_map* fmap = &ism->fmap->u.macho;
443
444 assert(ism->fmap->modtype == DMT_MACHO);
445 if (ism->sidx < 0 || ism->sidx >= ism->fmap->u.macho.num_sections || fmap->sect[ism->sidx].ignored)
446 return IMAGE_NO_MAP;
447
448 return macho_map_range(fmap, fmap->sect[ism->sidx].section.offset, fmap->sect[ism->sidx].section.size,
449 &fmap->sect[ism->sidx].mapped);
450}
451
452/******************************************************************
453 * macho_unmap_section
454 */
456{
457 struct macho_file_map* fmap = &ism->fmap->u.macho;
458
459 if (ism->sidx >= 0 && ism->sidx < fmap->num_sections && fmap->sect[ism->sidx].mapped != IMAGE_NO_MAP)
460 {
461 macho_unmap_range(&fmap->sect[ism->sidx].mapped, NULL, fmap, fmap->sect[ism->sidx].section.offset,
462 fmap->sect[ism->sidx].section.size);
463 }
464}
465
466/******************************************************************
467 * macho_get_map_rva
468 */
470{
471 if (ism->sidx < 0 || ism->sidx >= ism->fmap->u.macho.num_sections ||
472 ism->fmap->u.macho.sect[ism->sidx].ignored)
473 return 0;
474 return ism->fmap->u.macho.sect[ism->sidx].section.addr - ism->fmap->u.macho.segs_start;
475}
476
477/******************************************************************
478 * macho_get_map_size
479 */
480unsigned macho_get_map_size(const struct image_section_map* ism)
481{
482 if (ism->sidx < 0 || ism->sidx >= ism->fmap->u.macho.num_sections ||
483 ism->fmap->u.macho.sect[ism->sidx].ignored)
484 return 0;
485 return ism->fmap->u.macho.sect[ism->sidx].section.size;
486}
487
489{
496};
497
498/******************************************************************
499 * macho_map_load_commands
500 *
501 * Maps the load commands from a Mach-O file into memory
502 */
503static const struct macho_load_command* macho_map_load_commands(struct macho_file_map* fmap)
504{
505 if (fmap->load_commands == IMAGE_NO_MAP)
506 {
507 fmap->load_commands = (const struct macho_load_command*) macho_map_range(
508 fmap, fmap->header_size, fmap->commands_size, NULL);
509 TRACE("Mapped load commands: %p\n", fmap->load_commands);
510 }
511
512 return fmap->load_commands;
513}
514
515/******************************************************************
516 * macho_unmap_load_commands
517 *
518 * Unmaps the load commands of a Mach-O file from memory
519 */
520static void macho_unmap_load_commands(struct macho_file_map* fmap)
521{
522 if (fmap->load_commands != IMAGE_NO_MAP)
523 {
524 TRACE("Unmapping load commands: %p\n", fmap->load_commands);
525 macho_unmap_range(NULL, (const void**)&fmap->load_commands, fmap,
526 fmap->header_size, fmap->commands_size);
527 }
528}
529
530/******************************************************************
531 * macho_next_load_command
532 *
533 * Advance to the next load command
534 */
536{
537 return (const struct macho_load_command*)((const char*)lc + lc->cmdsize);
538}
539
540/******************************************************************
541 * macho_enum_load_commands
542 *
543 * Enumerates the load commands for a Mach-O file, selecting by
544 * the command type, calling a callback for each. If the callback
545 * returns <0, that indicates an error. If it returns >0, that means
546 * it's not interested in getting any more load commands.
547 * If this function returns <0, that's an error produced by the
548 * callback. If >=0, that's the count of load commands successfully
549 * processed.
550 */
551static int macho_enum_load_commands(struct image_file_map *ifm, unsigned cmd,
552 int (*cb)(struct image_file_map*, const struct macho_load_command*, void*),
553 void* user)
554{
555 struct macho_file_map* fmap = &ifm->u.macho;
556 const struct macho_load_command* lc;
557 int i;
558 int count = 0;
559
560 TRACE("(%p/%p, %u, %p, %p)\n", fmap, fmap->handle, cmd, cb, user);
561
562 if ((lc = macho_map_load_commands(fmap)) == IMAGE_NO_MAP) return -1;
563
564 TRACE("%u total commands\n", fmap->commands_count);
565
566 for (i = 0; i < fmap->commands_count; i++, lc = macho_next_load_command(lc))
567 {
568 int result;
569
570 if (cmd && cmd != lc->cmd) continue;
571 count++;
572
573 result = cb(ifm, lc, user);
574 TRACE("load_command[%d] (%p), cmd %u; callback => %d\n", i, lc, lc->cmd, result);
575 if (result) return (result < 0) ? result : count;
576 }
577
578 return count;
579}
580
581/******************************************************************
582 * macho_count_sections
583 *
584 * Callback for macho_enum_load_commands. Counts the number of
585 * significant sections in a Mach-O file. All commands are
586 * expected to be of LC_SEGMENT[_64] type.
587 */
588static int macho_count_sections(struct image_file_map* ifm, const struct macho_load_command* lc, void* user)
589{
590 char segname[16];
591 size_t nsects;
592
593 if (ifm->addr_size == 32)
594 {
595 const struct macho_segment_command32 *sc = (const struct macho_segment_command32 *)lc;
596 memcpy(segname, sc->segname, sizeof(segname));
597 nsects = sc->nsects;
598 }
599 else
600 {
601 const struct macho_segment_command *sc = (const struct macho_segment_command *)lc;
602 memcpy(segname, sc->segname, sizeof(segname));
603 nsects = sc->nsects;
604 }
605
606 TRACE("(%p/%p, %p, %p) segment %s\n", ifm, ifm->u.macho.handle, lc, user,
607 debugstr_an(segname, sizeof(segname)));
608
609 ifm->u.macho.num_sections += nsects;
610 return 0;
611}
612
613/******************************************************************
614 * macho_load_section_info
615 *
616 * Callback for macho_enum_load_commands. Accumulates the address
617 * range covered by the segments of a Mach-O file and builds the
618 * section map. All commands are expected to be of LC_SEGMENT[_64] type.
619 */
620static int macho_load_section_info(struct image_file_map* ifm, const struct macho_load_command* lc, void* user)
621{
622 struct macho_file_map* fmap = &ifm->u.macho;
623 struct section_info* info = user;
624 BOOL ignore;
625 int i;
627 UINT64 vmaddr, vmsize;
628 char segname[16];
629 size_t nsects;
630 const void *sections;
631
632 if (ifm->addr_size == 32)
633 {
634 const struct macho_segment_command32 *sc = (const struct macho_segment_command32 *)lc;
635 vmaddr = sc->vmaddr;
636 vmsize = sc->vmsize;
637 memcpy(segname, sc->segname, sizeof(segname));
638 nsects = sc->nsects;
639 sections = (const void *)(sc + 1);
640 }
641 else
642 {
643 const struct macho_segment_command *sc = (const struct macho_segment_command *)lc;
644 vmaddr = sc->vmaddr;
645 vmsize = sc->vmsize;
646 memcpy(segname, sc->segname, sizeof(segname));
647 nsects = sc->nsects;
648 sections = (const void *)(sc + 1);
649 }
650
651 TRACE("(%p/%p, %p, %p) before: 0x%08lx - 0x%08lx\n", fmap, fmap->handle, lc, user,
652 (ULONG_PTR)fmap->segs_start, (ULONG_PTR)fmap->segs_size);
653 TRACE("Segment command vm: 0x%08lx - 0x%08lx\n", (ULONG_PTR)vmaddr,
654 (ULONG_PTR)(vmaddr + vmsize));
655
656 /* Images in the dyld shared cache have their segments mapped non-contiguously.
657 We don't know how to properly locate any of the segments other than __TEXT,
658 so ignore them. */
659 ignore = (info->split_segs && strcmp(segname, "__TEXT"));
660
661 if (!strncmp(segname, "WINE_", 5))
662 TRACE("Ignoring special Wine segment %s\n", debugstr_an(segname, sizeof(segname)));
663 else if (!strncmp(segname, "__PAGEZERO", 10))
664 TRACE("Ignoring __PAGEZERO segment\n");
665 else if (ignore)
666 TRACE("Ignoring %s segment because image has split segments\n", segname);
667 else
668 {
669 /* If this segment starts before previously-known earliest, record new earliest. */
670 if (vmaddr < fmap->segs_start)
671 fmap->segs_start = vmaddr;
672
673 /* If this segment extends beyond previously-known furthest, record new furthest. */
674 tmp = (vmaddr + vmsize + page_mask) & ~page_mask;
675 if (fmap->segs_size < tmp) fmap->segs_size = tmp;
676
677 TRACE("after: 0x%08lx - 0x%08lx\n", (ULONG_PTR)fmap->segs_start, (ULONG_PTR)fmap->segs_size);
678 }
679
680 for (i = 0; i < nsects; i++)
681 {
682 if (ifm->addr_size == 32)
683 {
684 const struct macho_section32 *section = &((const struct macho_section32 *)sections)[i];
685 memcpy(fmap->sect[info->section_index].section.sectname, section->sectname, sizeof(section->sectname));
686 memcpy(fmap->sect[info->section_index].section.segname, section->segname, sizeof(section->segname));
687 fmap->sect[info->section_index].section.addr = section->addr;
688 fmap->sect[info->section_index].section.size = section->size;
689 fmap->sect[info->section_index].section.offset = section->offset;
690 fmap->sect[info->section_index].section.align = section->align;
691 fmap->sect[info->section_index].section.reloff = section->reloff;
692 fmap->sect[info->section_index].section.nreloc = section->nreloc;
693 fmap->sect[info->section_index].section.flags = section->flags;
694 }
695 else
696 fmap->sect[info->section_index].section = ((const struct macho_section *)sections)[i];
697
698 fmap->sect[info->section_index].mapped = IMAGE_NO_MAP;
699 fmap->sect[info->section_index].ignored = ignore;
700 info->section_index++;
701 }
702
703 return 0;
704}
705
706/******************************************************************
707 * find_uuid
708 *
709 * Callback for macho_enum_load_commands. Records the UUID load
710 * command of a Mach-O file.
711 */
712static int find_uuid(struct image_file_map* ifm, const struct macho_load_command* lc, void* user)
713{
714 ifm->u.macho.uuid = (const struct macho_uuid_command*)lc;
715 return 1;
716}
717
718/******************************************************************
719 * reset_file_map
720 */
721static inline void reset_file_map(struct image_file_map* ifm)
722{
723 struct macho_file_map* fmap = &ifm->u.macho;
724
725 fmap->handle = INVALID_HANDLE_VALUE;
726 fmap->dsym = NULL;
727 fmap->load_commands = IMAGE_NO_MAP;
728 fmap->uuid = NULL;
729 fmap->num_sections = 0;
730 fmap->sect = NULL;
731}
732
733/******************************************************************
734 * macho_map_file
735 *
736 * Maps a Mach-O file into memory (and checks it's a real Mach-O file)
737 */
738static BOOL macho_map_file(struct process *pcs, const WCHAR *filenameW,
739 BOOL split_segs, struct image_file_map* ifm)
740{
741 struct macho_file_map* fmap = &ifm->u.macho;
742 struct macho_header mach_header;
743 int i;
745 struct section_info info;
746 BOOL ret = FALSE;
748 UINT32 target_magic = (pcs->is_64bit) ? MACHO_MH_MAGIC_64 : MACHO_MH_MAGIC_32;
749 UINT32 target_cmd = (pcs->is_64bit) ? MACHO_LC_SEGMENT_64 : MACHO_LC_SEGMENT;
750 DWORD bytes_read;
751
752 struct
753 {
754 UINT32 magic; /* FAT_MAGIC or FAT_MAGIC_64 */
755 UINT32 nfat_arch; /* number of structs that follow */
756 } fat_header;
757
758 TRACE("(%s, %p)\n", debugstr_w(filenameW), fmap);
759
760 reset_file_map(ifm);
761
762 ifm->modtype = DMT_MACHO;
763 ifm->ops = &macho_file_map_ops;
764 ifm->alternate = NULL;
765 ifm->addr_size = (pcs->is_64bit) ? 64 : 32;
766 fmap->header_size = (pcs->is_64bit) ? sizeof(struct macho_header) : FIELD_OFFSET(struct macho_header, reserved);
767
768 if (!(filename = get_dos_file_name(filenameW))) return FALSE;
769
770 /* Now open the file, so that we can map it. */
772 if (fmap->handle == INVALID_HANDLE_VALUE)
773 {
774 TRACE("failed to open file %s: %d\n", debugstr_w(filename), errno);
775 goto done;
776 }
777
778 if (!ReadFile(fmap->handle, &fat_header, sizeof(fat_header), &bytes_read, NULL) || bytes_read != sizeof(fat_header))
779 {
780 TRACE("failed to read fat header: %u\n", GetLastError());
781 goto done;
782 }
783 TRACE("... got possible fat header\n");
784
785 /* Fat header is always in big-endian order. */
786 if (swap_ulong_be_to_host(fat_header.magic) == MACHO_FAT_MAGIC)
787 {
788 int narch = swap_ulong_be_to_host(fat_header.nfat_arch);
789 for (i = 0; i < narch; i++)
790 {
791 struct
792 {
793 UINT32 cputype; /* cpu specifier (int) */
794 UINT32 cpusubtype; /* machine specifier (int) */
795 UINT32 offset; /* file offset to this object file */
796 UINT32 size; /* size of this object file */
797 UINT32 align; /* alignment as a power of 2 */
798 } fat_arch;
799
800 if (!ReadFile(fmap->handle, &fat_arch, sizeof(fat_arch), &bytes_read, NULL) || bytes_read != sizeof(fat_arch))
801 goto done;
802 if (swap_ulong_be_to_host(fat_arch.cputype) == target_cpu)
803 {
804 fmap->arch_offset = swap_ulong_be_to_host(fat_arch.offset);
805 break;
806 }
807 }
808 if (i >= narch) goto done;
809 TRACE("... found target arch (%d)\n", target_cpu);
810 }
811 else
812 {
813 fmap->arch_offset = 0;
814 TRACE("... not a fat header\n");
815 }
816
817 /* Individual architecture (standalone or within a fat file) is in its native byte order. */
818 SetFilePointer(fmap->handle, fmap->arch_offset, 0, FILE_BEGIN);
819 if (!ReadFile(fmap->handle, &mach_header, fmap->header_size, &bytes_read, NULL)
820 || bytes_read != fmap->header_size)
821 goto done;
822 TRACE("... got possible Mach header\n");
823 /* and check for a Mach-O header */
824 if (mach_header.magic != target_magic || mach_header.cputype != target_cpu) goto done;
825 fmap->commands_size = mach_header.sizeofcmds;
826 fmap->commands_count = mach_header.ncmds;
827 /* Make sure the file type is one of the ones we expect. */
828 switch (mach_header.filetype)
829 {
830 case MACHO_MH_EXECUTE:
831 case MACHO_MH_DYLIB:
833 case MACHO_MH_BUNDLE:
834 case MACHO_MH_DSYM:
835 break;
836 default:
837 goto done;
838 }
839 TRACE("... verified Mach header\n");
840
841 fmap->num_sections = 0;
842 if (macho_enum_load_commands(ifm, target_cmd, macho_count_sections, NULL) < 0)
843 goto done;
844 TRACE("%d sections\n", fmap->num_sections);
845
846 fmap->sect = HeapAlloc(GetProcessHeap(), 0, fmap->num_sections * sizeof(fmap->sect[0]));
847 if (!fmap->sect)
848 goto done;
849
850 fmap->segs_size = 0;
851 fmap->segs_start = ~0L;
852
853 info.split_segs = split_segs;
854 info.section_index = 0;
855 if (macho_enum_load_commands(ifm, target_cmd, macho_load_section_info, &info) < 0)
856 {
857 fmap->num_sections = 0;
858 goto done;
859 }
860
861 fmap->segs_size -= fmap->segs_start;
862 TRACE("segs_start: 0x%08lx, segs_size: 0x%08lx\n", (ULONG_PTR)fmap->segs_start,
863 (ULONG_PTR)fmap->segs_size);
864
866 goto done;
867 if (fmap->uuid)
868 {
870 TRACE("UUID %s\n", format_uuid(fmap->uuid->uuid, uuid_string));
871 }
872 else
873 TRACE("no UUID found\n");
874
875 ret = TRUE;
876done:
877 if (!ret)
878 macho_unmap_file(ifm);
880 return ret;
881}
882
883/******************************************************************
884 * macho_unmap_file
885 *
886 * Unmaps a Mach-O file from memory (previously mapped with macho_map_file)
887 */
888static void macho_unmap_file(struct image_file_map* ifm)
889{
890 struct image_file_map* cursor;
891
892 TRACE("(%p/%p)\n", ifm, ifm->u.macho.handle);
893
894 cursor = ifm;
895 while (cursor)
896 {
897 struct image_file_map* next;
898
899 if (ifm->u.macho.handle != INVALID_HANDLE_VALUE)
900 {
901 struct image_section_map ism;
902
903 ism.fmap = ifm;
904 for (ism.sidx = 0; ism.sidx < ifm->u.macho.num_sections; ism.sidx++)
906
907 HeapFree(GetProcessHeap(), 0, ifm->u.macho.sect);
909 CloseHandle(ifm->u.macho.handle);
910 ifm->u.macho.handle = INVALID_HANDLE_VALUE;
911 }
912
913 next = cursor->u.macho.dsym;
914 if (cursor != ifm)
916 cursor = next;
917 }
918}
919
920/******************************************************************
921 * macho_sect_is_code
922 *
923 * Checks if a section, identified by sectidx which is a 1-based
924 * index into the sections of all segments, in order of load
925 * commands, contains code.
926 */
927static BOOL macho_sect_is_code(struct macho_file_map* fmap, unsigned char sectidx)
928{
929 BOOL ret;
930
931 TRACE("(%p/%p, %u)\n", fmap, fmap->handle, sectidx);
932
933 if (!sectidx) return FALSE;
934
935 sectidx--; /* convert from 1-based to 0-based */
936 if (sectidx >= fmap->num_sections || fmap->sect[sectidx].ignored) return FALSE;
937
938 ret = (!(fmap->sect[sectidx].section.flags & MACHO_SECTION_TYPE) &&
939 (fmap->sect[sectidx].section.flags & (MACHO_S_ATTR_PURE_INSTRUCTIONS | MACHO_S_ATTR_SOME_INSTRUCTIONS)));
940 TRACE("-> %d\n", ret);
941 return ret;
942}
943
944struct symtab_elt
945{
946 struct hash_table_elt ht_elt;
949 unsigned char is_code:1,
953};
954
956{
957 struct macho_file_map* fmap;
958 struct module* module;
959 struct pool pool;
961};
962
963/******************************************************************
964 * macho_stabs_def_cb
965 *
966 * Callback for stabs_parse. Collect symbol definitions.
967 */
968static void macho_stabs_def_cb(struct module* module, ULONG_PTR load_offset,
969 const char* name, ULONG_PTR offset,
970 BOOL is_public, BOOL is_global, unsigned char sectidx,
971 struct symt_compiland* compiland, void* user)
972{
973 struct macho_debug_info* mdi = user;
974 struct symtab_elt* ste;
975
976 TRACE("(%p, 0x%08lx, %s, 0x%08lx, %d, %d, %u, %p, %p/%p/%p)\n", module, load_offset,
978 compiland, mdi, mdi->fmap, mdi->fmap->handle);
979
980 /* Defer the creation of new non-debugging symbols until after we've
981 * finished parsing the stabs. */
982 ste = pool_alloc(&mdi->pool, sizeof(*ste));
983 ste->ht_elt.name = pool_strdup(&mdi->pool, name);
984 ste->compiland = compiland;
985 ste->addr = load_offset + offset;
986 ste->is_code = !!macho_sect_is_code(mdi->fmap, sectidx);
987 ste->is_public = !!is_public;
988 ste->is_global = !!is_global;
989 ste->used = 0;
990 hash_table_add(&mdi->ht_symtab, &ste->ht_elt);
991}
992
993/******************************************************************
994 * macho_parse_symtab
995 *
996 * Callback for macho_enum_load_commands. Processes the LC_SYMTAB
997 * load commands from the Mach-O file.
998 */
999static int macho_parse_symtab(struct image_file_map* ifm,
1000 const struct macho_load_command* lc, void* user)
1001{
1002 struct macho_file_map* fmap = &ifm->u.macho;
1003 const struct macho_symtab_command* sc = (const struct macho_symtab_command*)lc;
1004 struct macho_debug_info* mdi = user;
1005 const char* stabstr;
1006 int ret = 0;
1007 size_t stabsize = (ifm->addr_size == 32) ? sizeof(struct stab_nlist) : sizeof(struct macho64_nlist);
1008 const char *stab;
1009
1010 TRACE("(%p/%p, %p, %p) %u syms at 0x%08x, strings 0x%08x - 0x%08x\n", fmap, fmap->handle, lc,
1011 user, sc->nsyms, sc->symoff, sc->stroff, sc->stroff + sc->strsize);
1012
1013 if (!macho_map_ranges(fmap, sc->symoff, sc->nsyms * stabsize,
1014 sc->stroff, sc->strsize, (const void**)&stab, (const void**)&stabstr))
1015 return 0;
1016
1017 if (!stabs_parse(mdi->module,
1018 mdi->module->format_info[DFI_MACHO]->u.macho_info->load_addr - fmap->segs_start,
1019 stab, sc->nsyms, stabsize,
1020 stabstr, sc->strsize, macho_stabs_def_cb, mdi))
1021 ret = -1;
1022
1023 macho_unmap_ranges(fmap, sc->symoff, sc->nsyms * stabsize,
1024 sc->stroff, sc->strsize, (const void**)&stab, (const void**)&stabstr);
1025
1026 return ret;
1027}
1028
1029/******************************************************************
1030 * macho_finish_stabs
1031 *
1032 * Integrate the non-debugging symbols we've gathered into the
1033 * symbols that were generated during stabs parsing.
1034 */
1035static void macho_finish_stabs(struct module* module, struct hash_table* ht_symtab)
1036{
1037 struct hash_table_iter hti_ours;
1038 struct symtab_elt* ste;
1039 BOOL adjusted = FALSE;
1040
1041 TRACE("(%p, %p)\n", module, ht_symtab);
1042
1043 /* For each of our non-debugging symbols, see if it can provide some
1044 * missing details to one of the module's known symbols. */
1045 hash_table_iter_init(ht_symtab, &hti_ours, NULL);
1046 while ((ste = hash_table_iter_up(&hti_ours)))
1047 {
1048 struct hash_table_iter hti_modules;
1049 void* ptr;
1050 struct symt_ht* sym;
1051 struct symt_function* func;
1052 struct symt_data* data;
1053
1054 hash_table_iter_init(&module->ht_symbols, &hti_modules, ste->ht_elt.name);
1055 while ((ptr = hash_table_iter_up(&hti_modules)))
1056 {
1057 sym = CONTAINING_RECORD(ptr, struct symt_ht, hash_elt);
1058
1059 if (strcmp(sym->hash_elt.name, ste->ht_elt.name))
1060 continue;
1061
1062 switch (sym->symt.tag)
1063 {
1064 case SymTagFunction:
1065 func = (struct symt_function*)sym;
1066 if (func->address == module->format_info[DFI_MACHO]->u.macho_info->load_addr)
1067 {
1068 TRACE("Adjusting function %p/%s!%s from 0x%08lx to 0x%08lx\n", func,
1070 func->address, ste->addr);
1071 func->address = ste->addr;
1072 adjusted = TRUE;
1073 }
1074 if (func->address == ste->addr)
1075 ste->used = 1;
1076 break;
1077 case SymTagData:
1078 data = (struct symt_data*)sym;
1079 switch (data->kind)
1080 {
1081 case DataIsGlobal:
1082 case DataIsFileStatic:
1083 if (data->u.var.offset == module->format_info[DFI_MACHO]->u.macho_info->load_addr)
1084 {
1085 TRACE("Adjusting data symbol %p/%s!%s from 0x%08lx to 0x%08lx\n",
1087 data->u.var.offset, ste->addr);
1088 data->u.var.offset = ste->addr;
1089 adjusted = TRUE;
1090 }
1091 if (data->u.var.offset == ste->addr)
1092 {
1093 enum DataKind new_kind;
1094
1095 new_kind = ste->is_global ? DataIsGlobal : DataIsFileStatic;
1096 if (data->kind != new_kind)
1097 {
1098 WARN("Changing kind for %p/%s!%s from %d to %d\n", sym,
1100 (int)data->kind, (int)new_kind);
1101 data->kind = new_kind;
1102 adjusted = TRUE;
1103 }
1104 ste->used = 1;
1105 }
1106 break;
1107 default:;
1108 }
1109 break;
1110 default:
1111 TRACE("Ignoring tag %u\n", sym->symt.tag);
1112 break;
1113 }
1114 }
1115 }
1116
1117 if (adjusted)
1118 {
1119 /* since we may have changed some addresses, mark the module to be resorted */
1121 }
1122
1123 /* Mark any of our non-debugging symbols which fall on an already-used
1124 * address as "used". This allows us to skip them in the next loop,
1125 * below. We do this in separate loops because symt_new_* marks the
1126 * list as needing sorting and symt_find_nearest sorts if needed,
1127 * causing thrashing. */
1129 {
1130 hash_table_iter_init(ht_symtab, &hti_ours, NULL);
1131 while ((ste = hash_table_iter_up(&hti_ours)))
1132 {
1133 struct symt_ht* sym;
1134 ULONG64 addr;
1135
1136 if (ste->used) continue;
1137
1138 sym = symt_find_nearest(module, ste->addr);
1139 if (sym)
1140 symt_get_address(&sym->symt, &addr);
1141 if (sym && ste->addr == addr)
1142 {
1143 ULONG64 size = 0;
1144 DWORD kind = -1;
1145
1146 ste->used = 1;
1147
1148 /* If neither symbol has a correct size (ours never does), we
1149 * consider them both to be markers. No warning is needed in
1150 * that case.
1151 * Also, we check that we don't have two symbols, one local, the other
1152 * global, which is legal.
1153 */
1155 symt_get_info(module, &sym->symt, TI_GET_DATAKIND, &kind);
1156 if (size && kind == (ste->is_global ? DataIsGlobal : DataIsFileStatic))
1157 FIXME("Duplicate in %s: %s<%08lx> %s<%s-%s>\n",
1159 ste->ht_elt.name, ste->addr,
1160 sym->hash_elt.name,
1162 }
1163 }
1164 }
1165
1166 /* For any of our remaining non-debugging symbols which have no match
1167 * among the module's known symbols, add them as new symbols. */
1168 hash_table_iter_init(ht_symtab, &hti_ours, NULL);
1169 while ((ste = hash_table_iter_up(&hti_ours)))
1170 {
1171 if (!(dbghelp_options & SYMOPT_PUBLICS_ONLY) && !ste->used)
1172 {
1173 if (ste->is_code)
1174 {
1175 symt_new_function(module, ste->compiland, ste->ht_elt.name,
1176 ste->addr, 0, NULL);
1177 }
1178 else
1179 {
1180 struct location loc;
1181
1182 loc.kind = loc_absolute;
1183 loc.reg = 0;
1184 loc.offset = ste->addr;
1186 !ste->is_global, loc, 0, NULL);
1187 }
1188
1189 ste->used = 1;
1190 }
1191
1193 {
1194 symt_new_public(module, ste->compiland, ste->ht_elt.name, ste->is_code, ste->addr, 0);
1195 }
1196 }
1197}
1198
1199/******************************************************************
1200 * try_dsym
1201 *
1202 * Try to load a debug symbol file from the given path and check
1203 * if its UUID matches the UUID of an already-mapped file. If so,
1204 * stash the file map in the "dsym" field of the file and return
1205 * TRUE. If it can't be mapped or its UUID doesn't match, return
1206 * FALSE.
1207 */
1208static BOOL try_dsym(struct process *pcs, const WCHAR* path, struct macho_file_map* fmap)
1209{
1210 struct image_file_map dsym_ifm;
1211
1212 if (macho_map_file(pcs, path, FALSE, &dsym_ifm))
1213 {
1215
1216 if (dsym_ifm.u.macho.uuid && !memcmp(dsym_ifm.u.macho.uuid->uuid, fmap->uuid->uuid, sizeof(fmap->uuid->uuid)))
1217 {
1218 TRACE("found matching debug symbol file at %s\n", debugstr_w(path));
1219 fmap->dsym = HeapAlloc(GetProcessHeap(), 0, sizeof(dsym_ifm));
1220 *fmap->dsym = dsym_ifm;
1221 return TRUE;
1222 }
1223
1224 TRACE("candidate debug symbol file at %s has wrong UUID %s; ignoring\n", debugstr_w(path),
1225 format_uuid(dsym_ifm.u.macho.uuid->uuid, uuid_string));
1226
1227 macho_unmap_file(&dsym_ifm);
1228 }
1229 else
1230 TRACE("couldn't map file at %s\n", debugstr_w(path));
1231
1232 return FALSE;
1233}
1234
1235static const WCHAR dsym_subpath[] = {'\\','C','o','n','t','e','n','t','s',
1236 '\\','R','e','s','o','u','r','c','e','s',
1237 '\\','D','W','A','R','F','\\',0};
1238
1239static WCHAR *query_dsym(const GUID *uuid, const WCHAR *filename)
1240{
1242 WCHAR *ret = NULL;
1243 char buf[1024];
1244 HANDLE mgr;
1245 BOOL res;
1246
1248 OPEN_EXISTING, 0, 0);
1249 if (mgr == INVALID_HANDLE_VALUE) return NULL;
1250
1251 query = (void *)buf;
1252 res = DeviceIoControl( mgr, IOCTL_MOUNTMGR_QUERY_SYMBOL_FILE, (void*)uuid, sizeof(*uuid), query, sizeof(buf), NULL, NULL );
1253 if (!res && GetLastError() == ERROR_MORE_DATA)
1254 {
1255 size_t size = FIELD_OFFSET(MOUNTMGR_TARGET_NAME, DeviceName[query->DeviceNameLength]);
1257 if (query)
1258 res = DeviceIoControl( mgr, IOCTL_MOUNTMGR_QUERY_SYMBOL_FILE, (void*)uuid, sizeof(*uuid), query, size, NULL, NULL );
1259 }
1260 CloseHandle(mgr);
1261
1262 if (res && (ret = HeapAlloc(GetProcessHeap(), 0,
1263 query->DeviceNameLength + sizeof(dsym_subpath) + lstrlenW(filename) * sizeof(WCHAR))))
1264 {
1265 WCHAR *p = ret;
1266 memcpy(p, query->DeviceName, query->DeviceNameLength);
1267 p += query->DeviceNameLength / sizeof(WCHAR);
1268 memcpy(p, dsym_subpath, sizeof(dsym_subpath));
1269 p += ARRAY_SIZE(dsym_subpath) - 1;
1271 }
1272
1273 if (query != (void *)buf) HeapFree(GetProcessHeap(), 0, query);
1274 return ret;
1275}
1276
1277/******************************************************************
1278 * find_and_map_dsym
1279 *
1280 * Search for a debugging symbols file associated with a module and
1281 * map it. First look for a .dSYM bundle next to the module file
1282 * (e.g. <path>.dSYM/Contents/Resources/DWARF/<basename of path>)
1283 * as produced by dsymutil. Next, look for a .dwarf file next to
1284 * the module file (e.g. <path>.dwarf) as produced by
1285 * "dsymutil --flat". Finally, use Spotlight to search for a
1286 * .dSYM bundle with the same UUID as the module file.
1287 */
1288static void find_and_map_dsym(struct process *pcs, struct module* module)
1289{
1290 static const WCHAR dot_dsym[] = {'.','d','S','Y','M',0};
1291 static const WCHAR dot_dwarf[] = {'.','d','w','a','r','f',0};
1292 struct macho_file_map* fmap = &module->format_info[DFI_MACHO]->u.macho_info->file_map.u.macho;
1293 const WCHAR* p;
1294 size_t len;
1295 WCHAR* path = NULL;
1296
1297 /* Without a UUID, we can't verify that any debug info file we find corresponds
1298 to this file. Better to have no debug info than incorrect debug info. */
1299 if (!fmap->uuid)
1300 return;
1301
1304 path = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1305 if (!path)
1306 return;
1308 lstrcatW(path, dot_dsym);
1310 lstrcatW(path, p);
1311
1312 if (try_dsym(pcs, path, fmap))
1313 goto found;
1314
1316
1317 if (try_dsym(pcs, path, fmap))
1318 goto found;
1319
1321 if ((path = query_dsym((const GUID *)fmap->uuid->uuid, p))) try_dsym(pcs, path, fmap);
1322
1323found:
1325}
1326
1327/******************************************************************
1328 * image_uses_split_segs
1329 *
1330 * Determine if the Mach-O image loaded at a particular address in
1331 * the given process is in the dyld shared cache and therefore has
1332 * its segments mapped non-contiguously.
1333 *
1334 * The image header has to be loaded from the process's memory
1335 * because the relevant flag is only set in memory, not in the file.
1336 */
1338{
1339 BOOL split_segs = FALSE;
1340
1341 if (load_addr)
1342 {
1345 struct macho_header header;
1346
1348 header.magic == target_magic && header.cputype == target_cpu &&
1350 {
1351 split_segs = TRUE;
1352 }
1353 }
1354
1355 return split_segs;
1356}
1357
1358/******************************************************************
1359 * macho_load_debug_info
1360 *
1361 * Loads Mach-O debugging information from the module image file.
1362 */
1363static BOOL macho_load_debug_info(struct process *pcs, struct module* module)
1364{
1365 BOOL ret = FALSE;
1366 struct macho_debug_info mdi;
1367 int result;
1368 struct image_file_map *ifm;
1369 struct macho_file_map *fmap;
1370
1371 if (module->type != DMT_MACHO || !module->format_info[DFI_MACHO]->u.macho_info)
1372 {
1373 ERR("Bad Mach-O module '%s'\n", debugstr_w(module->module.LoadedImageName));
1374 return FALSE;
1375 }
1376
1377 ifm = &module->format_info[DFI_MACHO]->u.macho_info->file_map;
1378 fmap = &ifm->u.macho;
1379
1380 TRACE("(%p, %p/%p)\n", module, fmap, fmap->handle);
1381
1383
1385 {
1387
1388 if (dwarf2_parse(module, module->reloc_delta, NULL /* FIXME: some thunks to deal with ? */,
1389 &module->format_info[DFI_MACHO]->u.macho_info->file_map))
1390 ret = TRUE;
1391 }
1392
1393 mdi.fmap = fmap;
1394 mdi.module = module;
1395 pool_init(&mdi.pool, 65536);
1396 hash_table_init(&mdi.pool, &mdi.ht_symtab, 256);
1398 if (result > 0)
1399 ret = TRUE;
1400 else if (result < 0)
1401 WARN("Couldn't correctly read stabs\n");
1402
1403 if (!(dbghelp_options & SYMOPT_PUBLICS_ONLY) && fmap->dsym)
1404 {
1405 mdi.fmap = &fmap->dsym->u.macho;
1407 if (result > 0)
1408 ret = TRUE;
1409 else if (result < 0)
1410 WARN("Couldn't correctly read stabs\n");
1411 }
1412
1414
1415 pool_destroy(&mdi.pool);
1416 return ret;
1417}
1418
1419/******************************************************************
1420 * macho_fetch_file_info
1421 *
1422 * Gathers some more information for a Mach-O module from a given file
1423 */
1426{
1427 struct image_file_map fmap;
1428 BOOL split_segs;
1429
1430 TRACE("(%s, %p, %p, %p)\n", debugstr_w(name), base, size, checksum);
1431
1433 if (!macho_map_file(process, name, split_segs, &fmap)) return FALSE;
1434 if (base) *base = fmap.u.macho.segs_start;
1435 *size = fmap.u.macho.segs_size;
1436 *checksum = calc_crc32(fmap.u.macho.handle);
1437 macho_unmap_file(&fmap);
1438 return TRUE;
1439}
1440
1441/******************************************************************
1442 * macho_module_remove
1443 */
1444static void macho_module_remove(struct process* pcs, struct module_format* modfmt)
1445{
1446 macho_unmap_file(&modfmt->u.macho_info->file_map);
1447 HeapFree(GetProcessHeap(), 0, modfmt);
1448}
1449
1450/******************************************************************
1451 * macho_load_file
1452 *
1453 * Loads the information for Mach-O module stored in 'filename'.
1454 * The module has been loaded at 'load_addr' address.
1455 * returns
1456 * FALSE if the file cannot be found/opened or if the file doesn't
1457 * contain symbolic info (or this info cannot be read or parsed)
1458 * TRUE on success
1459 */
1460static BOOL macho_load_file(struct process* pcs, const WCHAR* filename,
1462{
1463 BOOL ret = TRUE;
1464 BOOL split_segs;
1465 struct image_file_map fmap;
1466
1467 TRACE("(%p/%p, %s, 0x%08lx, %p/0x%08x)\n", pcs, pcs->handle, debugstr_w(filename),
1469
1470 split_segs = image_uses_split_segs(pcs, load_addr);
1471 if (!macho_map_file(pcs, filename, split_segs, &fmap)) return FALSE;
1472
1474 {
1476 struct module_format* modfmt =
1477 HeapAlloc(GetProcessHeap(), 0, sizeof(struct module_format) + sizeof(struct macho_module_info));
1478 if (!modfmt) goto leave;
1479 if (!load_addr)
1480 load_addr = fmap.u.macho.segs_start;
1482 fmap.u.macho.segs_size, 0, calc_crc32(fmap.u.macho.handle));
1483 if (!macho_info->module)
1484 {
1485 HeapFree(GetProcessHeap(), 0, modfmt);
1486 goto leave;
1487 }
1488 macho_info->module->reloc_delta = macho_info->module->module.BaseOfImage - fmap.u.macho.segs_start;
1489 macho_module_info = (void*)(modfmt + 1);
1490 macho_info->module->format_info[DFI_MACHO] = modfmt;
1491
1492 modfmt->module = macho_info->module;
1493 modfmt->remove = macho_module_remove;
1494 modfmt->loc_compute = NULL;
1495 modfmt->u.macho_info = macho_module_info;
1496
1498
1500 reset_file_map(&fmap);
1502 macho_info->module->module.SymType = SymDeferred;
1503 else if (!macho_load_debug_info(pcs, macho_info->module))
1504 ret = FALSE;
1505
1506 macho_info->module->format_info[DFI_MACHO]->u.macho_info->in_use = 1;
1507 macho_info->module->format_info[DFI_MACHO]->u.macho_info->is_loader = 0;
1508 TRACE("module = %p\n", macho_info->module);
1509 }
1510
1512 {
1513 WCHAR* ptr;
1514 ptr = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(filename) + 1) * sizeof(WCHAR));
1515 if (ptr)
1516 {
1519 }
1520 else ret = FALSE;
1521 TRACE("module_name = %p %s\n", macho_info->module_name, debugstr_w(macho_info->module_name));
1522 }
1523leave:
1524 macho_unmap_file(&fmap);
1525
1526 TRACE(" => %d\n", ret);
1527 return ret;
1528}
1529
1531{
1535};
1536
1538{
1540 return macho_load_file(macho_load->process, filename, macho_load->load_addr, macho_load->macho_info);
1541}
1542
1543/******************************************************************
1544 * macho_search_and_load_file
1545 *
1546 * Lookup a file in standard Mach-O locations, and if found, load it
1547 */
1550 struct macho_info* macho_info)
1551{
1552 BOOL ret = FALSE;
1553 struct module* module;
1554 static const WCHAR S_libstdcPPW[] = {'l','i','b','s','t','d','c','+','+','\0'};
1555 const WCHAR* p;
1556 struct macho_load_params load_params;
1557
1558 TRACE("(%p/%p, %s, 0x%08lx, %p)\n", pcs, pcs->handle, debugstr_w(filename), load_addr,
1559 macho_info);
1560
1561 if (filename == NULL || *filename == '\0') return FALSE;
1563 {
1565 module->format_info[DFI_MACHO]->u.macho_info->in_use = 1;
1566 return module->module.SymType;
1567 }
1568
1569 if (wcsstr(filename, S_libstdcPPW)) return FALSE; /* We know we can't do it */
1570
1571 load_params.process = pcs;
1572 load_params.load_addr = load_addr;
1573 load_params.macho_info = macho_info;
1574
1575 /* Try DYLD_LIBRARY_PATH first. */
1576 p = file_name(filename);
1577 ret = search_unix_path(p, process_getenv(pcs, L"DYLD_LIBRARY_PATH"), macho_load_file_cb, &load_params);
1578
1579 /* Try the path as given. */
1580 if (!ret)
1582 /* Try DYLD_FALLBACK_LIBRARY_PATH, with just the filename (no directories). */
1583 if (!ret)
1584 {
1585 const WCHAR* fallback = process_getenv(pcs, L"DYLD_FALLBACK_LIBRARY_PATH");
1586 if (!fallback)
1587 fallback = L"/usr/local/lib:/lib:/usr/lib";
1588 ret = search_unix_path(p, fallback, macho_load_file_cb, &load_params);
1589 }
1590 if (!ret && p == filename)
1591 ret = search_dll_path(pcs, filename, macho_load_file_cb, &load_params);
1592
1593 return ret;
1594}
1595
1596/******************************************************************
1597 * macho_enum_modules_internal
1598 *
1599 * Enumerate Mach-O modules from a running process
1600 */
1602 const WCHAR* main_name,
1603 enum_modules_cb cb, void* user)
1604{
1605 union wine_all_image_infos image_infos;
1606 union wine_image_info* info_array = NULL;
1607 ULONG_PTR len;
1608 int i;
1609 char bufstr[256];
1610 WCHAR bufstrW[MAX_PATH];
1611 BOOL ret = FALSE;
1612
1613 TRACE("(%p/%p, %s, %p, %p)\n", pcs, pcs->handle, debugstr_w(main_name), cb,
1614 user);
1615
1616 if (pcs->is_64bit)
1617 len = sizeof(image_infos.infos64);
1618 else
1619 len = sizeof(image_infos.infos32);
1620 if (!pcs->dbg_hdr_addr ||
1621 !read_process_memory(pcs, pcs->dbg_hdr_addr, &image_infos, len))
1622 goto done;
1623 if (!pcs->is_64bit)
1624 {
1625 struct dyld_all_image_infos32 temp = image_infos.infos32;
1626 image_infos.infos64.infoArrayCount = temp.infoArrayCount;
1627 image_infos.infos64.infoArray = temp.infoArray;
1628 }
1629 if (!image_infos.infos64.infoArray)
1630 goto done;
1631 TRACE("Process has %u image infos at %s\n", image_infos.infos64.infoArrayCount, wine_dbgstr_longlong(image_infos.infos64.infoArray));
1632
1633 if (pcs->is_64bit)
1634 len = sizeof(info_array->info64);
1635 else
1636 len = sizeof(info_array->info32);
1637 len *= image_infos.infos64.infoArrayCount;
1638 info_array = HeapAlloc(GetProcessHeap(), 0, len);
1639 if (!info_array ||
1640 !read_process_memory(pcs, image_infos.infos64.infoArray, info_array, len))
1641 goto done;
1642 TRACE("... read image infos\n");
1643
1644 for (i = 0; i < image_infos.infos64.infoArrayCount; i++)
1645 {
1646 struct dyld_image_info64 info;
1647 if (pcs->is_64bit)
1648 info = info_array[i].info64;
1649 else
1650 {
1651 struct dyld_image_info32 *info32 = &info_array->info32 + i;
1652 info.imageLoadAddress = info32->imageLoadAddress;
1653 info.imageFilePath = info32->imageFilePath;
1654 }
1655 if (info.imageFilePath &&
1656 read_process_memory(pcs, info.imageFilePath, bufstr, sizeof(bufstr)))
1657 {
1658 bufstr[sizeof(bufstr) - 1] = '\0';
1659 TRACE("[%d] image file %s\n", i, debugstr_a(bufstr));
1660 MultiByteToWideChar(CP_UNIXCP, 0, bufstr, -1, bufstrW, ARRAY_SIZE(bufstrW));
1661 if (main_name && !bufstrW[0]) lstrcpyW(bufstrW, main_name);
1662 if (!cb(bufstrW, info.imageLoadAddress, user)) break;
1663 }
1664 }
1665
1666 ret = TRUE;
1667done:
1668 HeapFree(GetProcessHeap(), 0, info_array);
1669 return ret;
1670}
1671
1673{
1674 struct process* pcs;
1676};
1677
1679{
1680 struct macho_sync* ms = user;
1681
1682 TRACE("(%s, 0x%08lx, %p)\n", debugstr_w(name), addr, user);
1684 return TRUE;
1685}
1686
1687/******************************************************************
1688 * macho_synchronize_module_list
1689 *
1690 * Rescans the debuggee's modules list and synchronizes it with
1691 * the one from 'pcs', ie:
1692 * - if a module is in debuggee and not in pcs, it's loaded into pcs
1693 * - if a module is in pcs and not in debuggee, it's unloaded from pcs
1694 */
1696{
1697 struct module* module;
1698 struct macho_sync ms;
1699
1700 TRACE("(%p/%p)\n", pcs, pcs->handle);
1701
1702 for (module = pcs->lmodules; module; module = module->next)
1703 {
1704 if (module->type == DMT_MACHO && !module->is_virtual)
1705 module->format_info[DFI_MACHO]->u.macho_info->in_use = 0;
1706 }
1707
1708 ms.pcs = pcs;
1709 ms.macho_info.flags = MACHO_INFO_MODULE;
1711 return FALSE;
1712
1713 module = pcs->lmodules;
1714 while (module)
1715 {
1716 if (module->type == DMT_MACHO && !module->is_virtual &&
1717 !module->format_info[DFI_MACHO]->u.macho_info->in_use &&
1718 !module->format_info[DFI_MACHO]->u.macho_info->is_loader)
1719 {
1721 /* restart all over */
1722 module = pcs->lmodules;
1723 }
1724 else module = module->next;
1725 }
1726 return TRUE;
1727}
1728
1729/******************************************************************
1730 * macho_enum_modules
1731 *
1732 * Enumerates the Mach-O loaded modules from a running target (hProc)
1733 * This function doesn't require that someone has called SymInitialize
1734 * on this very process.
1735 */
1737{
1738 struct macho_info macho_info;
1739 BOOL ret;
1740
1741 TRACE("(%p, %p, %p)\n", process->handle, cb, user);
1746 return ret;
1747}
1748
1750{
1751 struct process* pcs;
1753 const WCHAR* name;
1755};
1756
1757/******************************************************************
1758 * macho_load_cb
1759 *
1760 * Callback for macho_load_module, used to walk the list of loaded
1761 * modules.
1762 */
1764{
1765 struct macho_load* ml = user;
1766 const WCHAR* p;
1767
1768 TRACE("(%s, 0x%08lx, %p)\n", debugstr_w(name), addr, user);
1769
1770 /* memcmp is needed for matches when bufstr contains also version information
1771 * ml->name: libc.so, name: libc.so.6.0
1772 */
1773 p = file_name(name);
1774 if (!memcmp(p, ml->name, lstrlenW(ml->name) * sizeof(WCHAR)))
1775 {
1777 return FALSE;
1778 }
1779 return TRUE;
1780}
1781
1782/******************************************************************
1783 * macho_load_module
1784 *
1785 * Loads a Mach-O module and stores it in process' module list.
1786 * Also, find module real name and load address from
1787 * the real loaded modules list in pcs address space.
1788 */
1789static struct module* macho_load_module(struct process* pcs, const WCHAR* name, ULONG_PTR addr)
1790{
1791 struct macho_load ml;
1792
1793 TRACE("(%p/%p, %s, 0x%08lx)\n", pcs, pcs->handle, debugstr_w(name), addr);
1794
1795 ml.macho_info.flags = MACHO_INFO_MODULE;
1796 ml.ret = FALSE;
1797
1798 if (pcs->dbg_hdr_addr) /* we're debugging a live target */
1799 {
1800 ml.pcs = pcs;
1801 /* do only the lookup from the filename, not the path (as we lookup module
1802 * name in the process' loaded module list)
1803 */
1804 ml.name = file_name(name);
1805 ml.ret = FALSE;
1806
1808 return NULL;
1809 }
1810 else if (addr)
1811 {
1812 ml.name = name;
1814 }
1815 if (!ml.ret) return NULL;
1816 assert(ml.macho_info.module);
1817 return ml.macho_info.module;
1818}
1819
1820/******************************************************************
1821 * macho_search_loader
1822 *
1823 * Lookup in a running Mach-O process the loader, and sets its Mach-O link
1824 * address (for accessing the list of loaded images) in pcs.
1825 * If flags is MACHO_INFO_MODULE, the module for the loader is also
1826 * added as a module into pcs.
1827 */
1829{
1830 BOOL ret = FALSE;
1831 union wine_all_image_infos image_infos;
1832 union wine_image_info image_info;
1833 unsigned int len;
1834 char path[1024];
1835 BOOL got_path = FALSE;
1836
1837 if (pcs->is_64bit)
1838 len = sizeof(image_infos.infos64);
1839 else
1840 len = sizeof(image_infos.infos32);
1841 if (read_process_memory(pcs, pcs->dbg_hdr_addr, &image_infos, len))
1842 {
1843 if (pcs->is_64bit)
1844 len = sizeof(image_info.info64);
1845 else
1846 {
1847 struct dyld_all_image_infos32 temp = image_infos.infos32;
1848 image_infos.infos64.infoArrayCount = temp.infoArrayCount;
1849 image_infos.infos64.infoArray = temp.infoArray;
1850 len = sizeof(image_info.info32);
1851 }
1852 if (image_infos.infos64.infoArray && image_infos.infos64.infoArrayCount &&
1853 read_process_memory(pcs, image_infos.infos64.infoArray, &image_info, len))
1854 {
1855 if (!pcs->is_64bit)
1856 {
1857 struct dyld_image_info32 temp = image_info.info32;
1858 image_info.info64.imageLoadAddress = temp.imageLoadAddress;
1859 image_info.info64.imageFilePath = temp.imageFilePath;
1860 }
1861 for (len = sizeof(path); image_info.info64.imageFilePath && len > 0; len /= 2)
1862 {
1863 if (read_process_memory(pcs, image_info.info64.imageFilePath, path, len))
1864 {
1865 path[len - 1] = 0;
1866 got_path = TRUE;
1867 TRACE("got executable path from target's dyld image info: %s\n", debugstr_a(path));
1868 break;
1869 }
1870 }
1871 }
1872 }
1873
1874 if (got_path)
1875 {
1876 WCHAR* pathW;
1877
1878 len = MultiByteToWideChar(CP_UNIXCP, 0, path, -1, NULL, 0);
1879 pathW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1880 if (pathW)
1881 {
1882 MultiByteToWideChar(CP_UNIXCP, 0, path, -1, pathW, len);
1883 ret = macho_load_file(pcs, pathW, 0, macho_info);
1884 HeapFree(GetProcessHeap(), 0, pathW);
1885 }
1886 }
1887
1888 if (!ret)
1889 {
1890 WCHAR *loader = get_wine_loader_name(pcs);
1891 ret = loader && macho_search_and_load_file(pcs, loader, 0, macho_info);
1892 heap_free(loader);
1893 }
1894 return ret;
1895}
1896
1897static const struct loader_ops macho_loader_ops =
1898{
1904};
1905
1906/******************************************************************
1907 * macho_read_wine_loader_dbg_info
1908 *
1909 * Try to find a decent wine executable which could have loaded the debuggee
1910 */
1912{
1913 struct macho_info macho_info;
1914
1915 TRACE("(%p/%p)\n", pcs, pcs->handle);
1916 pcs->dbg_hdr_addr = addr;
1918 if (!macho_search_loader(pcs, &macho_info)) return FALSE;
1919 macho_info.module->format_info[DFI_MACHO]->u.macho_info->is_loader = 1;
1921 pcs->loader = &macho_loader_ops;
1922 TRACE("Found macho debug header %#lx\n", pcs->dbg_hdr_addr);
1923 return TRUE;
1924}
unsigned long long UINT64
unsigned char UINT8
unsigned int UINT32
int strcmp(const char *String1, const char *String2)
Definition: utclib.c:469
int memcmp(void *Buffer1, void *Buffer2, ACPI_SIZE Count)
Definition: utclib.c:112
int strncmp(const char *String1, const char *String2, ACPI_SIZE Count)
Definition: utclib.c:534
static BOOL heap_free(void *mem)
Definition: appwiz.h:76
#define WINE_DEFAULT_DEBUG_CHANNEL(t)
Definition: precomp.h:23
void user(int argc, const char *argv[])
Definition: cmds.c:1350
#define ARRAY_SIZE(A)
Definition: main.h:20
#define FIXME(fmt,...)
Definition: precomp.h:53
#define WARN(fmt,...)
Definition: precomp.h:61
#define ERR(fmt,...)
Definition: precomp.h:57
#define leave
Definition: btrfs_drv.h:138
struct symt_function * symt_new_function(struct module *module, struct symt_compiland *parent, const char *name, ULONG_PTR addr, ULONG_PTR size, struct symt *type) DECLSPEC_HIDDEN
Definition: symbol.c:293
BOOL symt_get_info(struct module *module, const struct symt *type, IMAGEHLP_SYMBOL_TYPE_INFO req, void *pInfo) DECLSPEC_HIDDEN
Definition: type.c:536
void hash_table_init(struct pool *pool, struct hash_table *ht, unsigned num_buckets) DECLSPEC_HIDDEN
Definition: storage.c:334
BOOL search_dll_path(const struct process *process, const WCHAR *name, BOOL(*match)(void *, HANDLE, const WCHAR *), void *param) DECLSPEC_HIDDEN
Definition: path.c:697
BOOL dwarf2_parse(struct module *module, ULONG_PTR load_offset, const struct elf_thunk_area *thunks, struct image_file_map *fmap) DECLSPEC_HIDDEN
Definition: dwarf.c:3509
void * pool_alloc(struct pool *a, size_t len) DECLSPEC_HIDDEN
Definition: storage.c:89
BOOL stabs_parse(struct module *module, ULONG_PTR load_offset, const char *stabs, size_t nstab, size_t stabsize, const char *strs, int strtablen, stabs_def_cb callback, void *user) DECLSPEC_HIDDEN
Definition: stabs.c:1241
WCHAR * get_dos_file_name(const WCHAR *filename) DECLSPEC_HIDDEN
Definition: path.c:671
static BOOL read_process_memory(const struct process *process, UINT64 addr, void *buf, size_t size)
void pool_init(struct pool *a, size_t arena_size) DECLSPEC_HIDDEN
Definition: storage.c:43
void pool_destroy(struct pool *a) DECLSPEC_HIDDEN
Definition: storage.c:50
struct symt_public * symt_new_public(struct module *module, struct symt_compiland *parent, const char *typename, BOOL is_function, ULONG_PTR address, unsigned size) DECLSPEC_HIDDEN
Definition: symbol.c:224
@ DFI_MACHO
void hash_table_iter_init(const struct hash_table *ht, struct hash_table_iter *hti, const char *name) DECLSPEC_HIDDEN
Definition: storage.c:405
WCHAR * get_wine_loader_name(struct process *pcs) DECLSPEC_HIDDEN
Definition: module.c:150
BOOL(* enum_modules_cb)(const WCHAR *, ULONG_PTR addr, void *user)
struct symt_data * symt_new_global_variable(struct module *module, struct symt_compiland *parent, const char *name, unsigned is_static, struct location loc, ULONG_PTR size, struct symt *type) DECLSPEC_HIDDEN
Definition: symbol.c:256
struct module * module_is_already_loaded(const struct process *pcs, const WCHAR *imgname) DECLSPEC_HIDDEN
Definition: module.c:303
void * hash_table_iter_up(struct hash_table_iter *hti) DECLSPEC_HIDDEN
Definition: storage.c:422
BOOL symt_get_address(const struct symt *type, ULONG64 *addr) DECLSPEC_HIDDEN
Definition: type.c:119
@ loc_absolute
BOOL search_unix_path(const WCHAR *name, const WCHAR *path, BOOL(*match)(void *, HANDLE, const WCHAR *), void *param) DECLSPEC_HIDDEN
Definition: path.c:782
BOOL module_remove(struct process *pcs, struct module *module) DECLSPEC_HIDDEN
Definition: module.c:889
char * pool_strdup(struct pool *a, const char *str) DECLSPEC_HIDDEN
Definition: storage.c:126
void hash_table_add(struct hash_table *ht, struct hash_table_elt *elt) DECLSPEC_HIDDEN
Definition: storage.c:378
void module_set_module(struct module *module, const WCHAR *name) DECLSPEC_HIDDEN
Definition: module.c:142
struct module * module_new(struct process *pcs, const WCHAR *name, enum module_type type, BOOL virtual, DWORD64 addr, DWORD64 size, ULONG_PTR stamp, ULONG_PTR checksum) DECLSPEC_HIDDEN
Definition: module.c:198
@ DMT_MACHO
struct symt_ht * symt_find_nearest(struct module *module, DWORD_PTR addr) DECLSPEC_HIDDEN
Definition: symbol.c:903
#define ERROR_MORE_DATA
Definition: dderror.h:13
BOOL WINAPI DeviceIoControl(IN HANDLE hDevice, IN DWORD dwIoControlCode, IN LPVOID lpInBuffer OPTIONAL, IN DWORD nInBufferSize OPTIONAL, OUT LPVOID lpOutBuffer OPTIONAL, IN DWORD nOutBufferSize OPTIONAL, OUT LPDWORD lpBytesReturned OPTIONAL, IN LPOVERLAPPED lpOverlapped OPTIONAL)
Definition: deviceio.c:136
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
static cab_ULONG checksum(const cab_UBYTE *data, cab_UWORD bytes, cab_ULONG csum)
Definition: fdi.c:353
#define CloseHandle
Definition: compat.h:739
#define CP_UNIXCP
Definition: compat.h:79
#define GetProcessHeap()
Definition: compat.h:736
#define PAGE_READONLY
Definition: compat.h:138
#define FILE_BEGIN
Definition: compat.h:761
#define SYMOPT_NO_PUBLICS
Definition: compat.h:993
@ SymDeferred
Definition: compat.h:1061
@ SymExport
Definition: compat.h:1060
#define UnmapViewOfFile
Definition: compat.h:746
#define OPEN_EXISTING
Definition: compat.h:775
#define ReadFile(a, b, c, d, e)
Definition: compat.h:742
#define SetFilePointer
Definition: compat.h:743
#define lstrcpynA
Definition: compat.h:751
#define INVALID_HANDLE_VALUE
Definition: compat.h:731
#define HeapAlloc
Definition: compat.h:733
#define CreateFileMappingW(a, b, c, d, e, f)
Definition: compat.h:744
static __inline const char * debugstr_an(const char *s, int n)
Definition: compat.h:55
#define SYMOPT_PUBLICS_ONLY
Definition: compat.h:992
static __inline const char * wine_dbgstr_longlong(ULONGLONG ll)
Definition: compat.h:49
#define GENERIC_READ
Definition: compat.h:135
@ TI_GET_LENGTH
Definition: compat.h:1417
@ TI_GET_DATAKIND
Definition: compat.h:1423
@ SymTagFunction
Definition: compat.h:1586
@ SymTagData
Definition: compat.h:1588
#define MAX_PATH
Definition: compat.h:34
#define HeapFree(x, y, z)
Definition: compat.h:735
#define SYMOPT_DEFERRED_LOADS
Definition: compat.h:989
#define CreateFileW
Definition: compat.h:741
#define FILE_MAP_READ
Definition: compat.h:776
DataKind
Definition: compat.h:1647
@ DataIsGlobal
Definition: compat.h:1654
@ DataIsFileStatic
Definition: compat.h:1653
#define lstrcpyW
Definition: compat.h:749
#define MapViewOfFile
Definition: compat.h:745
#define MultiByteToWideChar
Definition: compat.h:110
#define FILE_SHARE_READ
Definition: compat.h:136
#define lstrlenW
Definition: compat.h:750
DWORD calc_crc32(HANDLE handle)
Definition: dbghelp.c:874
unsigned dbghelp_options
Definition: dbghelp.c:73
SYSTEM_INFO sysinfo
Definition: dbghelp.c:76
const WCHAR * process_getenv(const struct process *process, const WCHAR *name)
Definition: dbghelp.c:335
const WCHAR S_WineLoaderW[]
Definition: module.c:42
#define assert(x)
Definition: debug.h:53
r reserved
Definition: btrfs.c:3006
int align(int length, int align)
Definition: dsound8.c:36
unsigned int BOOL
Definition: ntddk_ex.h:94
unsigned long DWORD
Definition: ntddk_ex.h:95
GLuint GLuint GLsizei count
Definition: gl.h:1545
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: gl.h:1950
GLsizeiptr size
Definition: glext.h:5919
GLenum func
Definition: glext.h:6028
GLuint res
Definition: glext.h:9613
GLenum GLuint GLenum GLsizei const GLchar * buf
Definition: glext.h:7751
GLenum const GLvoid * addr
Definition: glext.h:9621
GLenum GLenum GLenum GLenum mapping
Definition: glext.h:9031
GLfloat GLfloat p
Definition: glext.h:8902
GLfloat param
Definition: glext.h:5796
GLenum GLsizei len
Definition: glext.h:6722
GLuint64EXT * result
Definition: glext.h:11304
GLintptr offset
Definition: glext.h:5920
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
const char cursor[]
Definition: icontest.c:13
#define IMAGE_NO_MAP
Definition: image_private.h:24
_CONST_RETURN wchar_t *__cdecl wcsstr(_In_z_ const wchar_t *_Str, _In_z_ const wchar_t *_SubStr)
Definition: msctf.idl:550
const char * filename
Definition: ioapi.h:137
#define debugstr_a
Definition: kernel32.h:31
#define debugstr_w
Definition: kernel32.h:32
LPWSTR WINAPI lstrcatW(LPWSTR lpString1, LPCWSTR lpString2)
Definition: lstring.c:274
static char * format_uuid(const UINT8 uuid[16], char out[UUID_STRING_LEN])
Definition: macho_module.c:201
#define MACHO_MH_BUNDLE
Definition: macho_module.c:160
#define MACHO_MH_DYLINKER
Definition: macho_module.c:159
static BOOL macho_enum_sync_cb(const WCHAR *name, ULONG_PTR addr, void *user)
#define MACHO_DYLD_IN_SHARED_CACHE
Definition: macho_module.c:148
static const struct macho_load_command * macho_map_load_commands(struct macho_file_map *fmap)
Definition: macho_module.c:503
#define UUID_STRING_LEN
Definition: macho_module.c:172
static const char * macho_map_range(const struct macho_file_map *fmap, ULONG_PTR offset, ULONG_PTR len, const char **base)
Definition: macho_module.c:238
static int find_uuid(struct image_file_map *ifm, const struct macho_load_command *lc, void *user)
Definition: macho_module.c:712
#define MACHO_MH_DSYM
Definition: macho_module.c:161
DWORD_PTR macho_get_map_rva(const struct image_section_map *ism)
Definition: macho_module.c:469
BOOL macho_read_wine_loader_dbg_info(struct process *pcs, ULONG_PTR addr)
static BOOL image_uses_split_segs(struct process *process, ULONG_PTR load_addr)
static BOOL macho_fetch_file_info(struct process *process, const WCHAR *name, ULONG_PTR load_addr, DWORD_PTR *base, DWORD *size, DWORD *checksum)
#define MACHO_LC_SEGMENT_64
Definition: macho_module.c:165
static int macho_enum_load_commands(struct image_file_map *ifm, unsigned cmd, int(*cb)(struct image_file_map *, const struct macho_load_command *, void *), void *user)
Definition: macho_module.c:551
#define MACHO_LC_SEGMENT
Definition: macho_module.c:163
static BOOL macho_synchronize_module_list(struct process *pcs)
static void find_and_map_dsym(struct process *pcs, struct module *module)
static void macho_stabs_def_cb(struct module *module, ULONG_PTR load_offset, const char *name, ULONG_PTR offset, BOOL is_public, BOOL is_global, unsigned char sectidx, struct symt_compiland *compiland, void *user)
Definition: macho_module.c:968
const char * macho_map_section(struct image_section_map *ism)
Definition: macho_module.c:440
static BOOL macho_find_section(struct image_file_map *ifm, const char *sectname, struct image_section_map *ism)
Definition: macho_module.c:432
static WCHAR * query_dsym(const GUID *uuid, const WCHAR *filename)
static BOOL macho_load_file(struct process *pcs, const WCHAR *filename, ULONG_PTR load_addr, struct macho_info *macho_info)
static void macho_unmap_ranges(const struct macho_file_map *fmap, ULONG_PTR offset1, ULONG_PTR len1, ULONG_PTR offset2, ULONG_PTR len2, const void **mapped1, const void **mapped2)
Definition: macho_module.c:358
static BOOL macho_search_loader(struct process *pcs, struct macho_info *macho_info)
#define MACHO_MH_MAGIC_64
Definition: macho_module.c:152
#define swap_ulong_be_to_host(n)
Definition: macho_module.c:135
static const struct macho_load_command * macho_next_load_command(const struct macho_load_command *lc)
Definition: macho_module.c:535
static BOOL macho_load_cb(const WCHAR *name, ULONG_PTR addr, void *user)
static void macho_unmap_range(const char **base, const void **mapped, const struct macho_file_map *fmap, ULONG_PTR offset, ULONG_PTR len)
Definition: macho_module.c:274
unsigned macho_get_map_size(const struct image_section_map *ism)
Definition: macho_module.c:480
#define MACHO_SECTION_TYPE
Definition: macho_module.c:168
static BOOL macho_map_ranges(const struct macho_file_map *fmap, ULONG_PTR offset1, ULONG_PTR len1, ULONG_PTR offset2, ULONG_PTR len2, const void **mapped1, const void **mapped2)
Definition: macho_module.c:306
static void macho_finish_stabs(struct module *module, struct hash_table *ht_symtab)
static int macho_load_section_info(struct image_file_map *ifm, const struct macho_load_command *lc, void *user)
Definition: macho_module.c:620
static const struct loader_ops macho_loader_ops
#define MACHO_S_ATTR_PURE_INSTRUCTIONS
Definition: macho_module.c:169
static BOOL macho_search_and_load_file(struct process *pcs, const WCHAR *filename, ULONG_PTR load_addr, struct macho_info *macho_info)
#define MACHO_S_ATTR_SOME_INSTRUCTIONS
Definition: macho_module.c:170
static BOOL macho_map_file(struct process *pcs, const WCHAR *filenameW, BOOL split_segs, struct image_file_map *ifm)
Definition: macho_module.c:738
static const WCHAR dsym_subpath[]
#define MACHO_MH_DYLIB
Definition: macho_module.c:158
#define MACHO_MH_EXECUTE
Definition: macho_module.c:157
void macho_unmap_section(struct image_section_map *ism)
Definition: macho_module.c:455
static BOOL try_dsym(struct process *pcs, const WCHAR *path, struct macho_file_map *fmap)
static BOOL macho_find_segment_section(struct image_file_map *ifm, const char *segname, const char *sectname, struct image_section_map *ism)
Definition: macho_module.c:395
static int macho_parse_symtab(struct image_file_map *ifm, const struct macho_load_command *lc, void *user)
Definition: macho_module.c:999
#define MACHO_MH_MAGIC_32
Definition: macho_module.c:151
#define MACHO_CPU_TYPE_X86_64
Definition: macho_module.c:155
static BOOL macho_sect_is_code(struct macho_file_map *fmap, unsigned char sectidx)
Definition: macho_module.c:927
#define MACHO_LC_UUID
Definition: macho_module.c:166
#define MACHO_INFO_MODULE
Definition: macho_module.c:189
static void macho_module_remove(struct process *pcs, struct module_format *modfmt)
static const struct image_file_map_ops macho_file_map_ops
Definition: macho_module.c:488
#define MACHO_LC_SYMTAB
Definition: macho_module.c:164
#define MACHO_CPU_TYPE_X86
Definition: macho_module.c:154
#define MACHO_FAT_MAGIC
Definition: macho_module.c:150
#define MACHO_INFO_NAME
Definition: macho_module.c:190
static void reset_file_map(struct image_file_map *ifm)
Definition: macho_module.c:721
static struct module * macho_load_module(struct process *pcs, const WCHAR *name, ULONG_PTR addr)
static void macho_unmap_load_commands(struct macho_file_map *fmap)
Definition: macho_module.c:520
static void macho_unmap_file(struct image_file_map *fmap)
Definition: macho_module.c:888
static BOOL macho_enum_modules_internal(const struct process *pcs, const WCHAR *main_name, enum_modules_cb cb, void *user)
static BOOL macho_load_file_cb(void *param, HANDLE handle, const WCHAR *filename)
static BOOL macho_load_debug_info(struct process *pcs, struct module *module)
static int macho_count_sections(struct image_file_map *ifm, const struct macho_load_command *lc, void *user)
Definition: macho_module.c:588
static void macho_calc_range(const struct macho_file_map *fmap, ULONG_PTR offset, ULONG_PTR len, ULONG_PTR *out_aligned_offset, ULONG_PTR *out_aligned_end, ULONG_PTR *out_misalign)
Definition: macho_module.c:217
static BOOL macho_enum_modules(struct process *process, enum_modules_cb cb, void *user)
int load_addr
Definition: mkisofs.c:104
#define memcpy(s1, s2, n)
Definition: mkisofs.h:878
unsigned __int64 ULONG64
Definition: imports.h:198
static PVOID ptr
Definition: dispmode.c:27
#define sprintf(buf, format,...)
Definition: sprintf.c:55
static const WCHAR filenameW[]
Definition: amstream.c:41
static HMODULE MODULEINFO DWORD cb
Definition: module.c:33
static UINT_PTR page_mask
Definition: virtual.c:49
struct section sections[2]
Definition: diskspace.c:792
static LPCWSTR file_name
Definition: protocol.c:147
#define MOUNTMGR_DOS_DEVICE_NAME
Definition: mountmgr.h:37
#define FILE_SHARE_WRITE
Definition: nt_native.h:681
#define GENERIC_WRITE
Definition: nt_native.h:90
#define L(x)
Definition: ntvdm.h:50
static unsigned __int64 next
Definition: rand_nt.c:6
static FILE * out
Definition: regtests2xml.c:44
static calc_node_t temp
Definition: rpn_ieee.c:38
#define errno
Definition: errno.h:18
static const char * uuid_string(const UUID *uuid)
Definition: header.c:146
#define TRACE(s)
Definition: solgame.cpp:4
WCHAR ModuleName[32]
Definition: compat.h:1076
WCHAR LoadedImageName[256]
Definition: compat.h:1078
SYM_TYPE SymType
Definition: compat.h:1075
DWORD dwPageSize
Definition: winbase.h:1198
DWORD dwAllocationGranularity
Definition: winbase.h:1204
Definition: ftp_var.h:139
UINT32 imageLoadAddress
Definition: macho_module.c:44
UINT32 imageFileModDate
Definition: macho_module.c:46
UINT64 imageFileModDate
Definition: macho_module.c:60
UINT64 imageLoadAddress
Definition: macho_module.c:58
enum module_type modtype
union image_file_map::@383 u
unsigned addr_size
struct image_file_map::@383::macho_file_map macho
struct image_file_map * alternate
struct image_file_map * dsym
const struct image_file_map_ops * ops
struct image_file_map * fmap
ULONG_PTR offset
unsigned reg
unsigned kind
struct module * module
Definition: macho_module.c:958
struct hash_table ht_symtab
Definition: macho_module.c:960
struct macho_file_map * fmap
Definition: macho_module.c:957
struct pool pool
Definition: macho_module.c:959
UINT32 sizeofcmds
Definition: macho_module.c:87
UINT32 cpusubtype
Definition: macho_module.c:84
UINT32 cputype
Definition: macho_module.c:83
UINT32 ncmds
Definition: macho_module.c:86
UINT32 reserved
Definition: macho_module.c:89
UINT32 filetype
Definition: macho_module.c:85
UINT32 magic
Definition: macho_module.c:82
UINT32 flags
Definition: macho_module.c:88
const WCHAR * module_name
Definition: macho_module.c:196
struct module * module
Definition: macho_module.c:195
unsigned flags
Definition: macho_module.c:194
struct process * process
struct macho_info * macho_info
struct macho_info macho_info
struct process * pcs
const WCHAR * name
unsigned short in_use
Definition: macho_module.c:179
ULONG_PTR load_addr
Definition: macho_module.c:178
struct image_file_map file_map
Definition: macho_module.c:177
unsigned short is_loader
Definition: macho_module.c:180
struct macho_info macho_info
struct process * pcs
struct module * module
struct macho_module_info * macho_info
void(* loc_compute)(struct process *pcs, const struct module_format *modfmt, const struct symt_function *func, struct location *loc)
union module_format::@372 u
void(* remove)(struct process *pcs, struct module_format *modfmt)
DWORD64 reloc_delta
unsigned short is_virtual
IMAGEHLP_MODULEW64 module
int sortlist_valid
struct module_format * format_info[DFI_LAST]
struct hash_table ht_symbols
struct module * next
enum module_type type
Definition: name.c:39
const struct loader_ops * loader
HANDLE handle
ULONG_PTR dbg_hdr_addr
unsigned int section_index
Definition: macho_module.c:186
Definition: parser.c:56
struct hash_table_elt hash_elt
struct hash_table_elt hash_elt
struct symt symt
unsigned char is_public
Definition: macho_module.c:950
struct hash_table_elt ht_elt
Definition: elf_module.c:69
unsigned used
Definition: elf_module.c:72
unsigned char is_code
Definition: macho_module.c:949
struct symt_compiland * compiland
Definition: elf_module.c:71
ULONG_PTR addr
Definition: macho_module.c:948
unsigned char used
Definition: macho_module.c:952
unsigned char is_global
Definition: macho_module.c:951
uint32_t DWORD_PTR
Definition: typedefs.h:65
#define FIELD_OFFSET(t, f)
Definition: typedefs.h:255
uint32_t ULONG_PTR
Definition: typedefs.h:65
#define CONTAINING_RECORD(address, type, field)
Definition: typedefs.h:260
struct dyld_all_image_infos32 infos32
Definition: macho_module.c:76
struct dyld_all_image_infos64 infos64
Definition: macho_module.c:77
struct dyld_image_info64 info64
Definition: macho_module.c:72
struct dyld_image_info32 info32
Definition: macho_module.c:71
int ret
_Must_inspect_result_ _In_ PWDFDEVICE_INIT _In_opt_ PCUNICODE_STRING DeviceName
Definition: wdfdevice.h:3275
target_cpu
Definition: widl.h:79
DWORD WINAPI GetLastError(void)
Definition: except.c:1042
__wchar_t WCHAR
Definition: xmlstorage.h:180