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 42 struct dyld_image_info32 43 { 44 UINT32 imageLoadAddress; /* const struct mach_header* */ 45 UINT32 imageFilePath; /* const char* */ 46 UINT32 imageFileModDate; /* uintptr_t */ 47 }; 48 49 struct dyld_all_image_infos32 50 { 51 UINT32 version; 52 UINT32 infoArrayCount; 53 UINT32 infoArray; /* const struct dyld_image_info* */ 54 }; 55 56 struct dyld_image_info64 57 { 58 UINT64 imageLoadAddress; /* const struct mach_header* */ 59 UINT64 imageFilePath; /* const char* */ 60 UINT64 imageFileModDate; /* uintptr_t */ 61 }; 62 63 struct dyld_all_image_infos64 64 { 65 UINT32 version; 66 UINT32 infoArrayCount; 67 UINT64 infoArray; /* const struct dyld_image_info* */ 68 }; 69 70 union wine_image_info { 71 struct dyld_image_info32 info32; 72 struct dyld_image_info64 info64; 73 }; 74 75 union wine_all_image_infos { 76 struct dyld_all_image_infos32 infos32; 77 struct dyld_all_image_infos64 infos64; 78 }; 79 80 struct macho_header 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 92 struct macho_segment_command 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 107 struct macho_segment_command32 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 122 struct macho_symtab_command 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 138 WINE_DEFAULT_DEBUG_CHANNEL(dbghelp_macho); 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 175 struct macho_module_info 176 { 177 struct image_file_map file_map; 178 ULONG_PTR load_addr; 179 unsigned short in_use : 1, 180 is_loader : 1; 181 }; 182 183 struct section_info 184 { 185 BOOL split_segs; 186 unsigned int section_index; 187 }; 188 189 #define MACHO_INFO_MODULE 0x0001 190 #define MACHO_INFO_NAME 0x0002 191 192 struct macho_info 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 199 static void macho_unmap_file(struct image_file_map* fmap); 200 201 static 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 */ 217 static void macho_calc_range(const struct macho_file_map* fmap, ULONG_PTR offset, 218 ULONG_PTR len, ULONG_PTR* out_aligned_offset, 219 ULONG_PTR* out_aligned_end, ULONG_PTR* out_misalign) 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 */ 238 static 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; 243 HANDLE mapping; 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); 255 CloseHandle(mapping); 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 */ 274 static void macho_unmap_range(const char** base, const void** mapped, const struct macho_file_map* fmap, 275 ULONG_PTR offset, ULONG_PTR len) 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) 295 *base = IMAGE_NO_MAP; 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 */ 306 static BOOL macho_map_ranges(const struct macho_file_map* fmap, 307 ULONG_PTR offset1, ULONG_PTR len1, 308 ULONG_PTR offset2, ULONG_PTR len2, 309 const void** mapped1, const void** mapped2) 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 */ 358 static void macho_unmap_ranges(const struct macho_file_map* fmap, 359 ULONG_PTR offset1, ULONG_PTR len1, 360 ULONG_PTR offset2, ULONG_PTR len2, 361 const void** mapped1, const void** mapped2) 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 */ 395 static 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 432 static 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 */ 440 const 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 */ 455 void macho_unmap_section(struct image_section_map* ism) 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 */ 469 DWORD_PTR macho_get_map_rva(const struct image_section_map* ism) 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 */ 480 unsigned 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 488 static const struct image_file_map_ops macho_file_map_ops = 489 { 490 macho_map_section, 491 macho_unmap_section, 492 macho_find_section, 493 macho_get_map_rva, 494 macho_get_map_size, 495 macho_unmap_file, 496 }; 497 498 /****************************************************************** 499 * macho_map_load_commands 500 * 501 * Maps the load commands from a Mach-O file into memory 502 */ 503 static 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 */ 520 static 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 */ 535 static const struct macho_load_command* macho_next_load_command(const struct macho_load_command* lc) 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 */ 551 static int macho_enum_load_commands(struct image_file_map *ifm, unsigned cmd, 552 int (*cb)(struct image_file_map*, const struct macho_load_command*, void*), 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 */ 588 static 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 */ 620 static 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; 626 ULONG_PTR tmp, page_mask = sysinfo.dwPageSize - 1; 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 */ 712 static 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 */ 721 static 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 */ 738 static 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; 744 WCHAR* filename; 745 struct section_info info; 746 BOOL ret = FALSE; 747 UINT32 target_cpu = (pcs->is_64bit) ? MACHO_CPU_TYPE_X86_64 : MACHO_CPU_TYPE_X86; 748 UINT32 target_magic = (pcs->is_64bit) ? MACHO_MH_MAGIC_64 : MACHO_MH_MAGIC_32; 749 UINT32 target_cmd = (pcs->is_64bit) ? MACHO_LC_SEGMENT_64 : MACHO_LC_SEGMENT; 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. */ 771 fmap->handle = CreateFileW(filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); 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: 832 case MACHO_MH_DYLINKER: 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 865 if (macho_enum_load_commands(ifm, MACHO_LC_UUID, find_uuid, NULL) < 0) 866 goto done; 867 if (fmap->uuid) 868 { 869 char uuid_string[UUID_STRING_LEN]; 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; 876 done: 877 if (!ret) 878 macho_unmap_file(ifm); 879 HeapFree(GetProcessHeap(), 0, filename); 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 */ 888 static 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++) 905 macho_unmap_section(&ism); 906 907 HeapFree(GetProcessHeap(), 0, ifm->u.macho.sect); 908 macho_unmap_load_commands(&ifm->u.macho); 909 CloseHandle(ifm->u.macho.handle); 910 ifm->u.macho.handle = INVALID_HANDLE_VALUE; 911 } 912 913 next = cursor->u.macho.dsym; 914 if (cursor != ifm) 915 HeapFree(GetProcessHeap(), 0, cursor); 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 */ 927 static 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 944 struct symtab_elt 945 { 946 struct hash_table_elt ht_elt; 947 struct symt_compiland* compiland; 948 ULONG_PTR addr; 949 unsigned char is_code:1, 950 is_public:1, 951 is_global:1, 952 used:1; 953 }; 954 955 struct macho_debug_info 956 { 957 struct macho_file_map* fmap; 958 struct module* module; 959 struct pool pool; 960 struct hash_table ht_symtab; 961 }; 962 963 /****************************************************************** 964 * macho_stabs_def_cb 965 * 966 * Callback for stabs_parse. Collect symbol definitions. 967 */ 968 static void macho_stabs_def_cb(struct module* module, ULONG_PTR load_offset, 969 const char* name, ULONG_PTR offset, 970 BOOL is_public, BOOL is_global, unsigned char sectidx, 971 struct symt_compiland* compiland, void* user) 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, 977 debugstr_a(name), offset, is_public, is_global, sectidx, 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 */ 999 static 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 */ 1035 static 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, 1069 debugstr_w(module->module.ModuleName), sym->hash_elt.name, 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", 1086 data, debugstr_w(module->module.ModuleName), sym->hash_elt.name, 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, 1099 debugstr_w(module->module.ModuleName), sym->hash_elt.name, 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 */ 1120 module->sortlist_valid = FALSE; 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. */ 1128 if (!(dbghelp_options & SYMOPT_PUBLICS_ONLY)) 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 */ 1154 symt_get_info(module, &sym->symt, TI_GET_LENGTH, &size); 1155 symt_get_info(module, &sym->symt, TI_GET_DATAKIND, &kind); 1156 if (size && kind == (ste->is_global ? DataIsGlobal : DataIsFileStatic)) 1157 FIXME("Duplicate in %s: %s<%08lx> %s<%s-%s>\n", 1158 debugstr_w(module->module.ModuleName), 1159 ste->ht_elt.name, ste->addr, 1160 sym->hash_elt.name, 1161 wine_dbgstr_longlong(addr), wine_dbgstr_longlong(size)); 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; 1185 symt_new_global_variable(module, ste->compiland, ste->ht_elt.name, 1186 !ste->is_global, loc, 0, NULL); 1187 } 1188 1189 ste->used = 1; 1190 } 1191 1192 if (ste->is_public && !(dbghelp_options & SYMOPT_NO_PUBLICS)) 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 */ 1208 static 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 { 1214 char uuid_string[UUID_STRING_LEN]; 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 1235 static 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 1239 static WCHAR *query_dsym(const GUID *uuid, const WCHAR *filename) 1240 { 1241 MOUNTMGR_TARGET_NAME *query; 1242 WCHAR *ret = NULL; 1243 char buf[1024]; 1244 HANDLE mgr; 1245 BOOL res; 1246 1247 mgr = CreateFileW(MOUNTMGR_DOS_DEVICE_NAME, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, 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]); 1256 query = HeapAlloc(GetProcessHeap(), 0, size); 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; 1270 lstrcpyW(p, filename); 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 */ 1288 static 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 1302 p = file_name(module->module.LoadedImageName); 1303 len = lstrlenW(module->module.LoadedImageName) + lstrlenW(dot_dsym) + lstrlenW(dsym_subpath) + lstrlenW(p) + 1; 1304 path = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); 1305 if (!path) 1306 return; 1307 lstrcpyW(path, module->module.LoadedImageName); 1308 lstrcatW(path, dot_dsym); 1309 lstrcatW(path, dsym_subpath); 1310 lstrcatW(path, p); 1311 1312 if (try_dsym(pcs, path, fmap)) 1313 goto found; 1314 1315 lstrcpyW(path + lstrlenW(module->module.LoadedImageName), dot_dwarf); 1316 1317 if (try_dsym(pcs, path, fmap)) 1318 goto found; 1319 1320 HeapFree(GetProcessHeap(), 0, path); 1321 if ((path = query_dsym((const GUID *)fmap->uuid->uuid, p))) try_dsym(pcs, path, fmap); 1322 1323 found: 1324 HeapFree(GetProcessHeap(), 0, path); 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 */ 1337 static BOOL image_uses_split_segs(struct process* process, ULONG_PTR load_addr) 1338 { 1339 BOOL split_segs = FALSE; 1340 1341 if (load_addr) 1342 { 1343 UINT32 target_cpu = (process->is_64bit) ? MACHO_CPU_TYPE_X86_64 : MACHO_CPU_TYPE_X86; 1344 UINT32 target_magic = (process->is_64bit) ? MACHO_MH_MAGIC_64 : MACHO_MH_MAGIC_32; 1345 struct macho_header header; 1346 1347 if (read_process_memory(process, load_addr, &header, FIELD_OFFSET(struct macho_header, reserved)) && 1348 header.magic == target_magic && header.cputype == target_cpu && 1349 header.flags & MACHO_DYLD_IN_SHARED_CACHE) 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 */ 1363 static 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 1382 module->module.SymType = SymExport; 1383 1384 if (!(dbghelp_options & SYMOPT_PUBLICS_ONLY)) 1385 { 1386 find_and_map_dsym(pcs, module); 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); 1397 result = macho_enum_load_commands(ifm, MACHO_LC_SYMTAB, macho_parse_symtab, &mdi); 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; 1406 result = macho_enum_load_commands(fmap->dsym, MACHO_LC_SYMTAB, macho_parse_symtab, &mdi); 1407 if (result > 0) 1408 ret = TRUE; 1409 else if (result < 0) 1410 WARN("Couldn't correctly read stabs\n"); 1411 } 1412 1413 macho_finish_stabs(module, &mdi.ht_symtab); 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 */ 1424 static BOOL macho_fetch_file_info(struct process* process, const WCHAR* name, ULONG_PTR load_addr, DWORD_PTR* base, 1425 DWORD* size, DWORD* checksum) 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 1432 split_segs = image_uses_split_segs(process, load_addr); 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 */ 1444 static 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 */ 1460 static BOOL macho_load_file(struct process* pcs, const WCHAR* filename, 1461 ULONG_PTR load_addr, struct macho_info* macho_info) 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), 1468 load_addr, macho_info, macho_info->flags); 1469 1470 split_segs = image_uses_split_segs(pcs, load_addr); 1471 if (!macho_map_file(pcs, filename, split_segs, &fmap)) return FALSE; 1472 1473 if (macho_info->flags & MACHO_INFO_MODULE) 1474 { 1475 struct macho_module_info *macho_module_info; 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; 1481 macho_info->module = module_new(pcs, filename, DMT_MACHO, FALSE, load_addr, 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 1497 macho_module_info->load_addr = load_addr; 1498 1499 macho_module_info->file_map = fmap; 1500 reset_file_map(&fmap); 1501 if (dbghelp_options & SYMOPT_DEFERRED_LOADS) 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 1511 if (macho_info->flags & MACHO_INFO_NAME) 1512 { 1513 WCHAR* ptr; 1514 ptr = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(filename) + 1) * sizeof(WCHAR)); 1515 if (ptr) 1516 { 1517 lstrcpyW(ptr, filename); 1518 macho_info->module_name = ptr; 1519 } 1520 else ret = FALSE; 1521 TRACE("module_name = %p %s\n", macho_info->module_name, debugstr_w(macho_info->module_name)); 1522 } 1523 leave: 1524 macho_unmap_file(&fmap); 1525 1526 TRACE(" => %d\n", ret); 1527 return ret; 1528 } 1529 1530 struct macho_load_params 1531 { 1532 struct process *process; 1533 ULONG_PTR load_addr; 1534 struct macho_info *macho_info; 1535 }; 1536 1537 static BOOL macho_load_file_cb(void *param, HANDLE handle, const WCHAR *filename) 1538 { 1539 struct macho_load_params *macho_load = param; 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 */ 1548 static BOOL macho_search_and_load_file(struct process* pcs, const WCHAR* filename, 1549 ULONG_PTR load_addr, 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; 1562 if ((module = module_is_already_loaded(pcs, filename))) 1563 { 1564 macho_info->module = module; 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) 1581 ret = macho_load_file(pcs, filename, load_addr, macho_info); 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 */ 1601 static BOOL macho_enum_modules_internal(const struct process* pcs, 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; 1667 done: 1668 HeapFree(GetProcessHeap(), 0, info_array); 1669 return ret; 1670 } 1671 1672 struct macho_sync 1673 { 1674 struct process* pcs; 1675 struct macho_info macho_info; 1676 }; 1677 1678 static BOOL macho_enum_sync_cb(const WCHAR* name, ULONG_PTR addr, void* user) 1679 { 1680 struct macho_sync* ms = user; 1681 1682 TRACE("(%s, 0x%08lx, %p)\n", debugstr_w(name), addr, user); 1683 macho_search_and_load_file(ms->pcs, name, addr, &ms->macho_info); 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 */ 1695 static BOOL macho_synchronize_module_list(struct process* pcs) 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; 1710 if (!macho_enum_modules_internal(pcs, NULL, macho_enum_sync_cb, &ms)) 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 { 1720 module_remove(pcs, module); 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 */ 1736 static BOOL macho_enum_modules(struct process* process, enum_modules_cb cb, void* user) 1737 { 1738 struct macho_info macho_info; 1739 BOOL ret; 1740 1741 TRACE("(%p, %p, %p)\n", process->handle, cb, user); 1742 macho_info.flags = MACHO_INFO_NAME; 1743 macho_info.module_name = NULL; 1744 ret = macho_enum_modules_internal(process, macho_info.module_name, cb, user); 1745 HeapFree(GetProcessHeap(), 0, (char*)macho_info.module_name); 1746 return ret; 1747 } 1748 1749 struct macho_load 1750 { 1751 struct process* pcs; 1752 struct macho_info macho_info; 1753 const WCHAR* name; 1754 BOOL ret; 1755 }; 1756 1757 /****************************************************************** 1758 * macho_load_cb 1759 * 1760 * Callback for macho_load_module, used to walk the list of loaded 1761 * modules. 1762 */ 1763 static BOOL macho_load_cb(const WCHAR* name, ULONG_PTR addr, void* user) 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 { 1776 ml->ret = macho_search_and_load_file(ml->pcs, name, addr, &ml->macho_info); 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 */ 1789 static 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 1807 if (!macho_enum_modules_internal(pcs, NULL, macho_load_cb, &ml)) 1808 return NULL; 1809 } 1810 else if (addr) 1811 { 1812 ml.name = name; 1813 ml.ret = macho_search_and_load_file(pcs, ml.name, addr, &ml.macho_info); 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 */ 1828 static BOOL macho_search_loader(struct process* pcs, struct macho_info* macho_info) 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 1897 static const struct loader_ops macho_loader_ops = 1898 { 1899 macho_synchronize_module_list, 1900 macho_load_module, 1901 macho_load_debug_info, 1902 macho_enum_modules, 1903 macho_fetch_file_info, 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 */ 1911 BOOL macho_read_wine_loader_dbg_info(struct process* pcs, ULONG_PTR addr) 1912 { 1913 struct macho_info macho_info; 1914 1915 TRACE("(%p/%p)\n", pcs, pcs->handle); 1916 pcs->dbg_hdr_addr = addr; 1917 macho_info.flags = MACHO_INFO_MODULE; 1918 if (!macho_search_loader(pcs, &macho_info)) return FALSE; 1919 macho_info.module->format_info[DFI_MACHO]->u.macho_info->is_loader = 1; 1920 module_set_module(macho_info.module, S_WineLoaderW); 1921 pcs->loader = &macho_loader_ops; 1922 TRACE("Found macho debug header %#lx\n", pcs->dbg_hdr_addr); 1923 return TRUE; 1924 } 1925