Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenmacho_module.c
Go to the documentation of this file.
00001 /* 00002 * File macho_module.c - processing of Mach-O files 00003 * Originally based on elf_module.c 00004 * 00005 * Copyright (C) 1996, Eric Youngdale. 00006 * 1999-2007 Eric Pouech 00007 * 2009 Ken Thomases, CodeWeavers Inc. 00008 * 00009 * This library is free software; you can redistribute it and/or 00010 * modify it under the terms of the GNU Lesser General Public 00011 * License as published by the Free Software Foundation; either 00012 * version 2.1 of the License, or (at your option) any later version. 00013 * 00014 * This library is distributed in the hope that it will be useful, 00015 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00017 * Lesser General Public License for more details. 00018 * 00019 * You should have received a copy of the GNU Lesser General Public 00020 * License along with this library; if not, write to the Free Software 00021 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 00022 */ 00023 00024 #include "config.h" 00025 #include "wine/port.h" 00026 00027 #include "dbghelp_private.h" 00028 00029 #ifdef HAVE_MACH_O_LOADER_H 00030 00031 #include <assert.h> 00032 #include <stdarg.h> 00033 #ifdef HAVE_SYS_STAT_H 00034 # include <sys/stat.h> 00035 #endif 00036 #ifdef HAVE_SYS_MMAN_H 00037 # include <sys/mman.h> 00038 #endif 00039 00040 #include <mach-o/fat.h> 00041 #include <mach-o/loader.h> 00042 #include <mach-o/nlist.h> 00043 00044 #ifdef HAVE_MACH_O_DYLD_IMAGES_H 00045 #include <mach-o/dyld_images.h> 00046 #else 00047 struct dyld_image_info { 00048 const struct mach_header *imageLoadAddress; 00049 const char *imageFilePath; 00050 uintptr_t imageFileModDate; 00051 }; 00052 00053 struct dyld_all_image_infos { 00054 uint32_t version; 00055 uint32_t infoArrayCount; 00056 const struct dyld_image_info *infoArray; 00057 void* notification; 00058 int processDetachedFromSharedRegion; 00059 }; 00060 #endif 00061 00062 #include "winternl.h" 00063 #include "wine/library.h" 00064 #include "wine/debug.h" 00065 00066 #ifdef WORDS_BIGENDIAN 00067 #define swap_ulong_be_to_host(n) (n) 00068 #else 00069 #define swap_ulong_be_to_host(n) (RtlUlongByteSwap(n)) 00070 #endif 00071 00072 WINE_DEFAULT_DEBUG_CHANNEL(dbghelp_macho); 00073 00074 00075 struct macho_module_info 00076 { 00077 unsigned long load_addr; 00078 unsigned short in_use : 1, 00079 is_loader : 1; 00080 }; 00081 00082 #define MACHO_INFO_DEBUG_HEADER 0x0001 00083 #define MACHO_INFO_MODULE 0x0002 00084 #define MACHO_INFO_NAME 0x0004 00085 00086 struct macho_info 00087 { 00088 unsigned flags; /* IN one (or several) of the MACHO_INFO constants */ 00089 unsigned long dbg_hdr_addr; /* OUT address of debug header (if MACHO_INFO_DEBUG_HEADER is set) */ 00090 struct module* module; /* OUT loaded module (if MACHO_INFO_MODULE is set) */ 00091 const WCHAR* module_name; /* OUT found module name (if MACHO_INFO_NAME is set) */ 00092 }; 00093 00094 /* structure holding information while handling a Mach-O image */ 00095 #define BITS_PER_ULONG (sizeof(ULONG) * 8) 00096 #define ULONGS_FOR_BITS(nbits) (((nbits) + BITS_PER_ULONG - 1) / BITS_PER_ULONG) 00097 struct macho_file_map 00098 { 00099 /* A copy of the Mach-O header for an individual architecture. */ 00100 struct mach_header mach_header; 00101 00102 /* The mapped load commands. */ 00103 const struct load_command* load_commands; 00104 00105 /* The portion of the file which is this architecture. mach_header was 00106 * read from arch_offset. */ 00107 unsigned arch_offset; 00108 unsigned arch_size; 00109 00110 /* The range of address space covered by all segments. */ 00111 size_t segs_start; 00112 size_t segs_size; 00113 00114 /* Map of which sections contain code. Sections are accessed using 1-based 00115 * index. Bit 0 of this bitset indicates if the bitset has been initialized. */ 00116 RTL_BITMAP sect_is_code; 00117 ULONG sect_is_code_buff[ULONGS_FOR_BITS(MAX_SECT + 1)]; 00118 00119 /* The file. */ 00120 int fd; 00121 }; 00122 00123 static void macho_unmap_file(struct macho_file_map* fmap); 00124 00125 /****************************************************************** 00126 * macho_calc_range 00127 * 00128 * For a range (offset & length) of a single architecture within 00129 * a Mach-O file, calculate the page-aligned range of the whole file 00130 * that encompasses it. For a fat binary, the architecture will 00131 * itself be offset within the file, so take that into account. 00132 */ 00133 static void macho_calc_range(const struct macho_file_map* fmap, unsigned offset, 00134 unsigned len, unsigned* out_aligned_offset, 00135 unsigned* out_aligned_end, unsigned* out_aligned_len, 00136 unsigned* out_misalign) 00137 { 00138 unsigned pagemask = getpagesize() - 1; 00139 unsigned file_offset, misalign; 00140 00141 file_offset = fmap->arch_offset + offset; 00142 misalign = file_offset & pagemask; 00143 *out_aligned_offset = file_offset - misalign; 00144 *out_aligned_end = (file_offset + len + pagemask) & ~pagemask; 00145 if (out_aligned_len) 00146 *out_aligned_len = *out_aligned_end - *out_aligned_offset; 00147 if (out_misalign) 00148 *out_misalign = misalign; 00149 } 00150 00151 /****************************************************************** 00152 * macho_map_range 00153 * 00154 * Maps a range (offset, length in bytes) from a Mach-O file into memory 00155 */ 00156 static const char* macho_map_range(const struct macho_file_map* fmap, unsigned offset, unsigned len) 00157 { 00158 unsigned misalign, aligned_offset, aligned_map_end, map_size; 00159 const void* aligned_ptr; 00160 00161 TRACE("(%p/%d, 0x%08x, 0x%08x)\n", fmap, fmap->fd, offset, len); 00162 00163 macho_calc_range(fmap, offset, len, &aligned_offset, &aligned_map_end, 00164 &map_size, &misalign); 00165 00166 aligned_ptr = mmap(NULL, map_size, PROT_READ, MAP_PRIVATE, fmap->fd, aligned_offset); 00167 00168 TRACE("Mapped (0x%08x - 0x%08x) to %p\n", aligned_offset, aligned_map_end, aligned_ptr); 00169 00170 if (aligned_ptr == MAP_FAILED) return MACHO_NO_MAP; 00171 return (const char*)aligned_ptr + misalign; 00172 } 00173 00174 /****************************************************************** 00175 * macho_unmap_range 00176 * 00177 * Unmaps a range (offset, length in bytes) of a Mach-O file from memory 00178 */ 00179 static void macho_unmap_range(const void** mapped, const struct macho_file_map* fmap, 00180 unsigned offset, unsigned len) 00181 { 00182 TRACE("(%p, %p/%d, 0x%08x, 0x%08x)\n", mapped, fmap, fmap->fd, offset, len); 00183 00184 if (mapped && *mapped != MACHO_NO_MAP) 00185 { 00186 unsigned misalign, aligned_offset, aligned_map_end, map_size; 00187 void* aligned_ptr; 00188 00189 macho_calc_range(fmap, offset, len, &aligned_offset, &aligned_map_end, 00190 &map_size, &misalign); 00191 00192 aligned_ptr = (char*)*mapped - misalign; 00193 if (munmap(aligned_ptr, map_size) < 0) 00194 WARN("Couldn't unmap the range\n"); 00195 TRACE("Unmapped (0x%08x - 0x%08x) from %p - %p\n", aligned_offset, aligned_map_end, aligned_ptr, (char*)aligned_ptr + map_size); 00196 *mapped = MACHO_NO_MAP; 00197 } 00198 } 00199 00200 /****************************************************************** 00201 * macho_map_ranges 00202 * 00203 * Maps two ranges (offset, length in bytes) from a Mach-O file 00204 * into memory. If the two ranges overlap, use one mmap so that 00205 * the munmap doesn't fragment the mapping. 00206 */ 00207 static BOOL macho_map_ranges(const struct macho_file_map* fmap, 00208 unsigned offset1, unsigned len1, 00209 unsigned offset2, unsigned len2, 00210 const void** mapped1, const void** mapped2) 00211 { 00212 unsigned aligned_offset1, aligned_map_end1; 00213 unsigned aligned_offset2, aligned_map_end2; 00214 00215 TRACE("(%p/%d, 0x%08x, 0x%08x, 0x%08x, 0x%08x, %p, %p)\n", fmap, fmap->fd, 00216 offset1, len1, offset2, len2, mapped1, mapped2); 00217 00218 macho_calc_range(fmap, offset1, len1, &aligned_offset1, &aligned_map_end1, NULL, NULL); 00219 macho_calc_range(fmap, offset2, len2, &aligned_offset2, &aligned_map_end2, NULL, NULL); 00220 00221 if (aligned_map_end1 < aligned_offset2 || aligned_map_end2 < aligned_offset1) 00222 { 00223 *mapped1 = macho_map_range(fmap, offset1, len1); 00224 if (*mapped1 != MACHO_NO_MAP) 00225 { 00226 *mapped2 = macho_map_range(fmap, offset2, len2); 00227 if (*mapped2 == MACHO_NO_MAP) 00228 macho_unmap_range(mapped1, fmap, offset1, len1); 00229 } 00230 } 00231 else 00232 { 00233 if (offset1 < offset2) 00234 { 00235 *mapped1 = macho_map_range(fmap, offset1, offset2 + len2 - offset1); 00236 if (*mapped1 != MACHO_NO_MAP) 00237 *mapped2 = (const char*)*mapped1 + offset2 - offset1; 00238 } 00239 else 00240 { 00241 *mapped2 = macho_map_range(fmap, offset2, offset1 + len1 - offset2); 00242 if (*mapped2 != MACHO_NO_MAP) 00243 *mapped1 = (const char*)*mapped2 + offset1 - offset2; 00244 } 00245 } 00246 00247 TRACE(" => %p, %p\n", *mapped1, *mapped2); 00248 00249 return (*mapped1 != MACHO_NO_MAP) && (*mapped2 != MACHO_NO_MAP); 00250 } 00251 00252 /****************************************************************** 00253 * macho_unmap_ranges 00254 * 00255 * Unmaps two ranges (offset, length in bytes) of a Mach-O file 00256 * from memory. Use for ranges which were mapped by 00257 * macho_map_ranges. 00258 */ 00259 static void macho_unmap_ranges(const struct macho_file_map* fmap, 00260 unsigned offset1, unsigned len1, 00261 unsigned offset2, unsigned len2, 00262 const void** mapped1, const void** mapped2) 00263 { 00264 unsigned aligned_offset1, aligned_map_end1; 00265 unsigned aligned_offset2, aligned_map_end2; 00266 00267 TRACE("(%p/%d, 0x%08x, 0x%08x, 0x%08x, 0x%08x, %p/%p, %p/%p)\n", fmap, fmap->fd, 00268 offset1, len1, offset2, len2, mapped1, *mapped1, mapped2, *mapped2); 00269 00270 macho_calc_range(fmap, offset1, len1, &aligned_offset1, &aligned_map_end1, NULL, NULL); 00271 macho_calc_range(fmap, offset2, len2, &aligned_offset2, &aligned_map_end2, NULL, NULL); 00272 00273 if (aligned_map_end1 < aligned_offset2 || aligned_map_end2 < aligned_offset1) 00274 { 00275 macho_unmap_range(mapped1, fmap, offset1, len1); 00276 macho_unmap_range(mapped2, fmap, offset2, len2); 00277 } 00278 else 00279 { 00280 if (offset1 < offset2) 00281 { 00282 macho_unmap_range(mapped1, fmap, offset1, offset2 + len2 - offset1); 00283 *mapped2 = MACHO_NO_MAP; 00284 } 00285 else 00286 { 00287 macho_unmap_range(mapped2, fmap, offset2, offset1 + len1 - offset2); 00288 *mapped1 = MACHO_NO_MAP; 00289 } 00290 } 00291 } 00292 00293 /****************************************************************** 00294 * macho_map_load_commands 00295 * 00296 * Maps the load commands from a Mach-O file into memory 00297 */ 00298 static const struct load_command* macho_map_load_commands(struct macho_file_map* fmap) 00299 { 00300 if (fmap->load_commands == MACHO_NO_MAP) 00301 { 00302 fmap->load_commands = (const struct load_command*) macho_map_range( 00303 fmap, sizeof(fmap->mach_header), fmap->mach_header.sizeofcmds); 00304 TRACE("Mapped load commands: %p\n", fmap->load_commands); 00305 } 00306 00307 return fmap->load_commands; 00308 } 00309 00310 /****************************************************************** 00311 * macho_unmap_load_commands 00312 * 00313 * Unmaps the load commands of a Mach-O file from memory 00314 */ 00315 static void macho_unmap_load_commands(struct macho_file_map* fmap) 00316 { 00317 if (fmap->load_commands != MACHO_NO_MAP) 00318 { 00319 TRACE("Unmapping load commands: %p\n", fmap->load_commands); 00320 macho_unmap_range((const void**)&fmap->load_commands, fmap, 00321 sizeof(fmap->mach_header), fmap->mach_header.sizeofcmds); 00322 } 00323 } 00324 00325 /****************************************************************** 00326 * macho_next_load_command 00327 * 00328 * Advance to the next load command 00329 */ 00330 static const struct load_command* macho_next_load_command(const struct load_command* lc) 00331 { 00332 return (const struct load_command*)((const char*)lc + lc->cmdsize); 00333 } 00334 00335 /****************************************************************** 00336 * macho_enum_load_commands 00337 * 00338 * Enumerates the load commands for a Mach-O file, selecting by 00339 * the command type, calling a callback for each. If the callback 00340 * returns <0, that indicates an error. If it returns >0, that means 00341 * it's not interested in getting any more load commands. 00342 * If this function returns <0, that's an error produced by the 00343 * callback. If >=0, that's the count of load commands successfully 00344 * processed. 00345 */ 00346 static int macho_enum_load_commands(struct macho_file_map* fmap, unsigned cmd, 00347 int (*cb)(struct macho_file_map*, const struct load_command*, void*), 00348 void* user) 00349 { 00350 const struct load_command* lc; 00351 int i; 00352 int count = 0; 00353 00354 TRACE("(%p/%d, %u, %p, %p)\n", fmap, fmap->fd, cmd, cb, user); 00355 00356 if ((lc = macho_map_load_commands(fmap)) == MACHO_NO_MAP) return -1; 00357 00358 TRACE("%d total commands\n", fmap->mach_header.ncmds); 00359 00360 for (i = 0; i < fmap->mach_header.ncmds; i++, lc = macho_next_load_command(lc)) 00361 { 00362 int result; 00363 00364 if (cmd && cmd != lc->cmd) continue; 00365 count++; 00366 00367 result = cb(fmap, lc, user); 00368 TRACE("load_command[%d] (%p), cmd %u; callback => %d\n", i, lc, lc->cmd, result); 00369 if (result) return (result < 0) ? result : count; 00370 } 00371 00372 return count; 00373 } 00374 00375 /****************************************************************** 00376 * macho_accum_segs_range 00377 * 00378 * Callback for macho_enum_load_commands. Accumulates the address 00379 * range covered by the segments of a Mach-O file. All commands 00380 * are expected to be of LC_SEGMENT type. 00381 */ 00382 static int macho_accum_segs_range(struct macho_file_map* fmap, 00383 const struct load_command* lc, void* user) 00384 { 00385 const struct segment_command* sc = (const struct segment_command*)lc; 00386 unsigned tmp, page_mask = getpagesize() - 1; 00387 00388 TRACE("(%p/%d, %p, %p) before: 0x%08x - 0x%08x\n", fmap, fmap->fd, lc, user, 00389 (unsigned)fmap->segs_start, (unsigned)fmap->segs_size); 00390 TRACE("Segment command vm: 0x%08x - 0x%08x\n", (unsigned)sc->vmaddr, 00391 (unsigned)sc->vmaddr + sc->vmsize); 00392 00393 if (!strncmp(sc->segname, "WINE_", 5)) 00394 { 00395 TRACE("Ignoring special Wine segment %s\n", debugstr_an(sc->segname, sizeof(sc->segname))); 00396 return 0; 00397 } 00398 00399 /* If this segment starts before previously-known earliest, record 00400 * new earliest. */ 00401 if (sc->vmaddr < fmap->segs_start) 00402 fmap->segs_start = sc->vmaddr; 00403 00404 /* If this segment extends beyond previously-known furthest, record 00405 * new furthest. */ 00406 tmp = (sc->vmaddr + sc->vmsize + page_mask) & ~page_mask; 00407 if (fmap->segs_size < tmp) fmap->segs_size = tmp; 00408 00409 TRACE("after: 0x%08x - 0x%08x\n", (unsigned)fmap->segs_start, (unsigned)fmap->segs_size); 00410 00411 return 0; 00412 } 00413 00414 /****************************************************************** 00415 * macho_map_file 00416 * 00417 * Maps a Mach-O file into memory (and checks it's a real Mach-O file) 00418 */ 00419 static BOOL macho_map_file(const WCHAR* filenameW, struct macho_file_map* fmap) 00420 { 00421 struct fat_header fat_header; 00422 struct stat statbuf; 00423 int i; 00424 char* filename; 00425 unsigned len; 00426 BOOL ret = FALSE; 00427 00428 TRACE("(%s, %p)\n", debugstr_w(filenameW), fmap); 00429 00430 fmap->fd = -1; 00431 fmap->load_commands = MACHO_NO_MAP; 00432 RtlInitializeBitMap(&fmap->sect_is_code, fmap->sect_is_code_buff, MAX_SECT + 1); 00433 00434 len = WideCharToMultiByte(CP_UNIXCP, 0, filenameW, -1, NULL, 0, NULL, NULL); 00435 if (!(filename = HeapAlloc(GetProcessHeap(), 0, len))) return FALSE; 00436 WideCharToMultiByte(CP_UNIXCP, 0, filenameW, -1, filename, len, NULL, NULL); 00437 00438 /* check that the file exists */ 00439 if (stat(filename, &statbuf) == -1 || S_ISDIR(statbuf.st_mode)) goto done; 00440 00441 /* Now open the file, so that we can mmap() it. */ 00442 if ((fmap->fd = open(filename, O_RDONLY)) == -1) goto done; 00443 00444 if (read(fmap->fd, &fat_header, sizeof(fat_header)) != sizeof(fat_header)) 00445 goto done; 00446 TRACE("... got possible fat header\n"); 00447 00448 /* Fat header is always in big-endian order. */ 00449 if (swap_ulong_be_to_host(fat_header.magic) == FAT_MAGIC) 00450 { 00451 int narch = swap_ulong_be_to_host(fat_header.nfat_arch); 00452 for (i = 0; i < narch; i++) 00453 { 00454 struct fat_arch fat_arch; 00455 if (read(fmap->fd, &fat_arch, sizeof(fat_arch)) != sizeof(fat_arch)) 00456 goto done; 00457 if (swap_ulong_be_to_host(fat_arch.cputype) == CPU_TYPE_X86) 00458 { 00459 fmap->arch_offset = swap_ulong_be_to_host(fat_arch.offset); 00460 fmap->arch_size = swap_ulong_be_to_host(fat_arch.size); 00461 break; 00462 } 00463 } 00464 if (i >= narch) goto done; 00465 TRACE("... found x86 arch\n"); 00466 } 00467 else 00468 { 00469 fmap->arch_offset = 0; 00470 fmap->arch_size = statbuf.st_size; 00471 TRACE("... not a fat header\n"); 00472 } 00473 00474 /* Individual architecture (standalone or within a fat file) is in its native byte order. */ 00475 lseek(fmap->fd, fmap->arch_offset, SEEK_SET); 00476 if (read(fmap->fd, &fmap->mach_header, sizeof(fmap->mach_header)) != sizeof(fmap->mach_header)) 00477 goto done; 00478 TRACE("... got possible Mach header\n"); 00479 /* and check for a Mach-O header */ 00480 if (fmap->mach_header.magic != MH_MAGIC || 00481 fmap->mach_header.cputype != CPU_TYPE_X86) goto done; 00482 /* Make sure the file type is one of the ones we expect. */ 00483 switch (fmap->mach_header.filetype) 00484 { 00485 case MH_EXECUTE: 00486 case MH_DYLIB: 00487 case MH_DYLINKER: 00488 case MH_BUNDLE: 00489 break; 00490 default: 00491 goto done; 00492 } 00493 TRACE("... verified Mach x86 header\n"); 00494 00495 fmap->segs_size = 0; 00496 fmap->segs_start = ~0L; 00497 00498 if (macho_enum_load_commands(fmap, LC_SEGMENT, macho_accum_segs_range, NULL) < 0) 00499 goto done; 00500 00501 fmap->segs_size -= fmap->segs_start; 00502 TRACE("segs_start: 0x%08x, segs_size: 0x%08x\n", (unsigned)fmap->segs_start, 00503 (unsigned)fmap->segs_size); 00504 00505 ret = TRUE; 00506 done: 00507 if (!ret) 00508 macho_unmap_file(fmap); 00509 HeapFree(GetProcessHeap(), 0, filename); 00510 return ret; 00511 } 00512 00513 /****************************************************************** 00514 * macho_unmap_file 00515 * 00516 * Unmaps a Mach-O file from memory (previously mapped with macho_map_file) 00517 */ 00518 static void macho_unmap_file(struct macho_file_map* fmap) 00519 { 00520 TRACE("(%p/%d)\n", fmap, fmap->fd); 00521 if (fmap->fd != -1) 00522 { 00523 macho_unmap_load_commands(fmap); 00524 close(fmap->fd); 00525 fmap->fd = -1; 00526 } 00527 } 00528 00529 /****************************************************************** 00530 * macho_fill_sect_is_code 00531 * 00532 * Callback for macho_enum_load_commands. Determines which segments 00533 * of a Mach-O file contain code. All commands are expected to be 00534 * of LC_SEGMENT type. 00535 */ 00536 static int macho_fill_sect_is_code(struct macho_file_map* fmap, 00537 const struct load_command* lc, void* user) 00538 { 00539 const struct segment_command* sc = (const struct segment_command*)lc; 00540 const struct section* sections; 00541 int* cursect = user; 00542 int i; 00543 00544 TRACE("(%p/%d, %p, %p/%d) scanning %u sections\n", fmap, fmap->fd, lc, 00545 cursect, *cursect, sc->nsects); 00546 00547 sections = (const struct section*)(sc + 1); 00548 for (i = 0; i < sc->nsects; i++) 00549 { 00550 if (*cursect > MAX_SECT) return -1; 00551 (*cursect)++; 00552 00553 if (!(sections[i].flags & SECTION_TYPE) && 00554 (sections[i].flags & (S_ATTR_PURE_INSTRUCTIONS|S_ATTR_SOME_INSTRUCTIONS))) 00555 RtlSetBits(&fmap->sect_is_code, *cursect, 1); 00556 else 00557 RtlClearBits(&fmap->sect_is_code, *cursect, 1); 00558 TRACE("Section %d (%d of this segment) is%s code\n", *cursect, i, 00559 (RtlAreBitsSet(&fmap->sect_is_code, *cursect, 1) ? "" : " not")); 00560 } 00561 00562 return 0; 00563 } 00564 00565 /****************************************************************** 00566 * macho_sect_is_code 00567 * 00568 * Checks if a section, identified by sectidx which is a 1-based 00569 * index into the sections of all segments, in order of load 00570 * commands, contains code. 00571 */ 00572 static BOOL macho_sect_is_code(struct macho_file_map* fmap, unsigned char sectidx) 00573 { 00574 TRACE("(%p/%d, %u)\n", fmap, fmap->fd, sectidx); 00575 00576 if (!RtlAreBitsSet(&fmap->sect_is_code, 0, 1)) 00577 { 00578 int cursect = 0; 00579 if (macho_enum_load_commands(fmap, LC_SEGMENT, macho_fill_sect_is_code, &cursect) < 0) 00580 WARN("Couldn't load sect_is_code map\n"); 00581 RtlSetBits(&fmap->sect_is_code, 0, 1); 00582 } 00583 00584 return RtlAreBitsSet(&fmap->sect_is_code, sectidx, 1); 00585 } 00586 00587 struct symtab_elt 00588 { 00589 struct hash_table_elt ht_elt; 00590 struct symt_compiland* compiland; 00591 unsigned long addr; 00592 unsigned char is_code:1, 00593 is_public:1, 00594 is_global:1, 00595 used:1; 00596 }; 00597 00598 struct macho_debug_info 00599 { 00600 struct macho_file_map* fmap; 00601 struct module* module; 00602 struct pool pool; 00603 struct hash_table ht_symtab; 00604 }; 00605 00606 /****************************************************************** 00607 * macho_stabs_def_cb 00608 * 00609 * Callback for stabs_parse. Collect symbol definitions. 00610 */ 00611 static void macho_stabs_def_cb(struct module* module, unsigned long load_offset, 00612 const char* name, unsigned long offset, 00613 BOOL is_public, BOOL is_global, unsigned char sectidx, 00614 struct symt_compiland* compiland, void* user) 00615 { 00616 struct macho_debug_info* mdi = user; 00617 struct symtab_elt* ste; 00618 00619 TRACE("(%p, 0x%08lx, %s, 0x%08lx, %d, %d, %u, %p, %p/%p/%d)\n", module, load_offset, 00620 debugstr_a(name), offset, is_public, is_global, sectidx, 00621 compiland, mdi, mdi->fmap, mdi->fmap->fd); 00622 00623 /* Defer the creation of new non-debugging symbols until after we've 00624 * finished parsing the stabs. */ 00625 ste = pool_alloc(&mdi->pool, sizeof(*ste)); 00626 ste->ht_elt.name = pool_strdup(&mdi->pool, name); 00627 ste->compiland = compiland; 00628 ste->addr = load_offset + offset; 00629 ste->is_code = !!macho_sect_is_code(mdi->fmap, sectidx); 00630 ste->is_public = !!is_public; 00631 ste->is_global = !!is_global; 00632 ste->used = 0; 00633 hash_table_add(&mdi->ht_symtab, &ste->ht_elt); 00634 } 00635 00636 /****************************************************************** 00637 * macho_parse_symtab 00638 * 00639 * Callback for macho_enum_load_commands. Processes the LC_SYMTAB 00640 * load commands from the Mach-O file. 00641 */ 00642 static int macho_parse_symtab(struct macho_file_map* fmap, 00643 const struct load_command* lc, void* user) 00644 { 00645 const struct symtab_command* sc = (const struct symtab_command*)lc; 00646 struct macho_debug_info* mdi = user; 00647 const struct nlist* stab; 00648 const char* stabstr; 00649 int ret = 0; 00650 00651 TRACE("(%p/%d, %p, %p) %u syms at 0x%08x, strings 0x%08x - 0x%08x\n", fmap, fmap->fd, lc, 00652 user, sc->nsyms, sc->symoff, sc->stroff, sc->stroff + sc->strsize); 00653 00654 if (!macho_map_ranges(fmap, sc->symoff, sc->nsyms * sizeof(struct nlist), 00655 sc->stroff, sc->strsize, (const void**)&stab, (const void**)&stabstr)) 00656 return 0; 00657 00658 if (!stabs_parse(mdi->module, 00659 mdi->module->format_info[DFI_MACHO]->u.macho_info->load_addr - fmap->segs_start, 00660 stab, sc->nsyms * sizeof(struct nlist), 00661 stabstr, sc->strsize, macho_stabs_def_cb, mdi)) 00662 ret = -1; 00663 00664 macho_unmap_ranges(fmap, sc->symoff, sc->nsyms * sizeof(struct nlist), 00665 sc->stroff, sc->strsize, (const void**)&stab, (const void**)&stabstr); 00666 00667 return ret; 00668 } 00669 00670 /****************************************************************** 00671 * macho_finish_stabs 00672 * 00673 * Integrate the non-debugging symbols we've gathered into the 00674 * symbols that were generated during stabs parsing. 00675 */ 00676 static void macho_finish_stabs(struct module* module, struct hash_table* ht_symtab) 00677 { 00678 struct hash_table_iter hti_ours; 00679 struct symtab_elt* ste; 00680 BOOL adjusted = FALSE; 00681 00682 TRACE("(%p, %p)\n", module, ht_symtab); 00683 00684 /* For each of our non-debugging symbols, see if it can provide some 00685 * missing details to one of the module's known symbols. */ 00686 hash_table_iter_init(ht_symtab, &hti_ours, NULL); 00687 while ((ste = hash_table_iter_up(&hti_ours))) 00688 { 00689 struct hash_table_iter hti_modules; 00690 void* ptr; 00691 struct symt_ht* sym; 00692 struct symt_function* func; 00693 struct symt_data* data; 00694 00695 hash_table_iter_init(&module->ht_symbols, &hti_modules, ste->ht_elt.name); 00696 while ((ptr = hash_table_iter_up(&hti_modules))) 00697 { 00698 sym = GET_ENTRY(ptr, struct symt_ht, hash_elt); 00699 00700 if (strcmp(sym->hash_elt.name, ste->ht_elt.name)) 00701 continue; 00702 00703 switch (sym->symt.tag) 00704 { 00705 case SymTagFunction: 00706 func = (struct symt_function*)sym; 00707 if (func->address == module->format_info[DFI_MACHO]->u.macho_info->load_addr) 00708 { 00709 TRACE("Adjusting function %p/%s!%s from 0x%08lx to 0x%08lx\n", func, 00710 debugstr_w(module->module.ModuleName), sym->hash_elt.name, 00711 func->address, ste->addr); 00712 func->address = ste->addr; 00713 adjusted = TRUE; 00714 } 00715 if (func->address == ste->addr) 00716 ste->used = 1; 00717 break; 00718 case SymTagData: 00719 data = (struct symt_data*)sym; 00720 switch (data->kind) 00721 { 00722 case DataIsGlobal: 00723 case DataIsFileStatic: 00724 if (data->u.var.offset == module->format_info[DFI_MACHO]->u.macho_info->load_addr) 00725 { 00726 TRACE("Adjusting data symbol %p/%s!%s from 0x%08lx to 0x%08lx\n", 00727 data, debugstr_w(module->module.ModuleName), sym->hash_elt.name, 00728 data->u.var.offset, ste->addr); 00729 data->u.var.offset = ste->addr; 00730 adjusted = TRUE; 00731 } 00732 if (data->u.var.offset == ste->addr) 00733 { 00734 enum DataKind new_kind; 00735 00736 new_kind = ste->is_global ? DataIsGlobal : DataIsFileStatic; 00737 if (data->kind != new_kind) 00738 { 00739 WARN("Changing kind for %p/%s!%s from %d to %d\n", sym, 00740 debugstr_w(module->module.ModuleName), sym->hash_elt.name, 00741 (int)data->kind, (int)new_kind); 00742 data->kind = new_kind; 00743 adjusted = TRUE; 00744 } 00745 ste->used = 1; 00746 } 00747 break; 00748 default:; 00749 } 00750 break; 00751 default: 00752 TRACE("Ignoring tag %u\n", sym->symt.tag); 00753 break; 00754 } 00755 } 00756 } 00757 00758 if (adjusted) 00759 { 00760 /* since we may have changed some addresses, mark the module to be resorted */ 00761 module->sortlist_valid = FALSE; 00762 } 00763 00764 /* Mark any of our non-debugging symbols which fall on an already-used 00765 * address as "used". This allows us to skip them in the next loop, 00766 * below. We do this in separate loops because symt_new_* marks the 00767 * list as needing sorting and symt_find_nearest sorts if needed, 00768 * causing thrashing. */ 00769 if (!(dbghelp_options & SYMOPT_PUBLICS_ONLY)) 00770 { 00771 hash_table_iter_init(ht_symtab, &hti_ours, NULL); 00772 while ((ste = hash_table_iter_up(&hti_ours))) 00773 { 00774 struct symt_ht* sym; 00775 ULONG64 addr; 00776 00777 if (ste->used) continue; 00778 00779 sym = symt_find_nearest(module, ste->addr); 00780 if (sym) 00781 symt_get_address(&sym->symt, &addr); 00782 if (sym && ste->addr == addr) 00783 { 00784 ULONG64 size = 0; 00785 DWORD kind = -1; 00786 00787 ste->used = 1; 00788 00789 /* If neither symbol has a correct size (ours never does), we 00790 * consider them both to be markers. No warning is needed in 00791 * that case. 00792 * Also, we check that we don't have two symbols, one local, the other 00793 * global, which is legal. 00794 */ 00795 symt_get_info(module, &sym->symt, TI_GET_LENGTH, &size); 00796 symt_get_info(module, &sym->symt, TI_GET_DATAKIND, &kind); 00797 if (size && kind == (ste->is_global ? DataIsGlobal : DataIsFileStatic)) 00798 FIXME("Duplicate in %s: %s<%08lx> %s<%s-%s>\n", 00799 debugstr_w(module->module.ModuleName), 00800 ste->ht_elt.name, ste->addr, 00801 sym->hash_elt.name, 00802 wine_dbgstr_longlong(addr), wine_dbgstr_longlong(size)); 00803 } 00804 } 00805 } 00806 00807 /* For any of our remaining non-debugging symbols which have no match 00808 * among the module's known symbols, add them as new symbols. */ 00809 hash_table_iter_init(ht_symtab, &hti_ours, NULL); 00810 while ((ste = hash_table_iter_up(&hti_ours))) 00811 { 00812 if (!(dbghelp_options & SYMOPT_PUBLICS_ONLY) && !ste->used) 00813 { 00814 if (ste->is_code) 00815 { 00816 symt_new_function(module, ste->compiland, ste->ht_elt.name, 00817 ste->addr, 0, NULL); 00818 } 00819 else 00820 { 00821 struct location loc; 00822 00823 loc.kind = loc_absolute; 00824 loc.reg = 0; 00825 loc.offset = ste->addr; 00826 symt_new_global_variable(module, ste->compiland, ste->ht_elt.name, 00827 !ste->is_global, loc, 0, NULL); 00828 } 00829 00830 ste->used = 1; 00831 } 00832 00833 if (ste->is_public && !(dbghelp_options & SYMOPT_NO_PUBLICS)) 00834 { 00835 symt_new_public(module, ste->compiland, ste->ht_elt.name, ste->addr, 0); 00836 } 00837 } 00838 } 00839 00840 /****************************************************************** 00841 * macho_load_debug_info_from_map 00842 * 00843 * Loads the symbolic information from a Mach-O module. 00844 * Returns 00845 * FALSE if the file doesn't contain symbolic info (or this info 00846 * cannot be read or parsed) 00847 * TRUE on success 00848 */ 00849 static BOOL macho_load_debug_info_from_map(struct module* module, 00850 struct macho_file_map* fmap) 00851 { 00852 BOOL ret = FALSE; 00853 struct macho_debug_info mdi; 00854 int result; 00855 00856 TRACE("(%p, %p/%d)\n", module, fmap, fmap->fd); 00857 00858 module->module.SymType = SymExport; 00859 00860 mdi.fmap = fmap; 00861 mdi.module = module; 00862 pool_init(&mdi.pool, 65536); 00863 hash_table_init(&mdi.pool, &mdi.ht_symtab, 256); 00864 result = macho_enum_load_commands(fmap, LC_SYMTAB, macho_parse_symtab, &mdi); 00865 if (result > 0) 00866 ret = TRUE; 00867 else if (result < 0) 00868 WARN("Couldn't correctly read stabs\n"); 00869 00870 macho_finish_stabs(module, &mdi.ht_symtab); 00871 00872 pool_destroy(&mdi.pool); 00873 return ret; 00874 } 00875 00876 /****************************************************************** 00877 * macho_load_debug_info 00878 * 00879 * Loads Mach-O debugging information from the module image file. 00880 */ 00881 BOOL macho_load_debug_info(struct module* module, struct macho_file_map* fmap) 00882 { 00883 BOOL ret = TRUE; 00884 struct macho_file_map my_fmap; 00885 00886 TRACE("(%p, %p/%d)\n", module, fmap, fmap ? fmap->fd : -1); 00887 00888 if (module->type != DMT_MACHO || !module->format_info[DFI_MACHO]->u.macho_info) 00889 { 00890 ERR("Bad Mach-O module '%s'\n", debugstr_w(module->module.LoadedImageName)); 00891 return FALSE; 00892 } 00893 00894 if (!fmap) 00895 { 00896 fmap = &my_fmap; 00897 ret = macho_map_file(module->module.LoadedImageName, fmap); 00898 } 00899 if (ret) 00900 ret = macho_load_debug_info_from_map(module, fmap); 00901 00902 if (fmap == &my_fmap) macho_unmap_file(fmap); 00903 return ret; 00904 } 00905 00906 /****************************************************************** 00907 * macho_fetch_file_info 00908 * 00909 * Gathers some more information for a Mach-O module from a given file 00910 */ 00911 BOOL macho_fetch_file_info(const WCHAR* name, DWORD_PTR* base, 00912 DWORD* size, DWORD* checksum) 00913 { 00914 struct macho_file_map fmap; 00915 00916 TRACE("(%s, %p, %p, %p)\n", debugstr_w(name), base, size, checksum); 00917 00918 if (!macho_map_file(name, &fmap)) return FALSE; 00919 if (base) *base = fmap.segs_start; 00920 *size = fmap.segs_size; 00921 *checksum = calc_crc32(fmap.fd); 00922 macho_unmap_file(&fmap); 00923 return TRUE; 00924 } 00925 00926 /****************************************************************** 00927 * macho_load_file 00928 * 00929 * Loads the information for Mach-O module stored in 'filename'. 00930 * The module has been loaded at 'load_addr' address. 00931 * returns 00932 * FALSE if the file cannot be found/opened or if the file doesn't 00933 * contain symbolic info (or this info cannot be read or parsed) 00934 * TRUE on success 00935 */ 00936 static BOOL macho_load_file(struct process* pcs, const WCHAR* filename, 00937 unsigned long load_addr, struct macho_info* macho_info) 00938 { 00939 BOOL ret = TRUE; 00940 struct macho_file_map fmap; 00941 00942 TRACE("(%p/%p, %s, 0x%08lx, %p/0x%08x)\n", pcs, pcs->handle, debugstr_w(filename), 00943 load_addr, macho_info, macho_info->flags); 00944 00945 if (!macho_map_file(filename, &fmap)) return FALSE; 00946 00947 /* Find the dynamic loader's table of images loaded into the process. 00948 */ 00949 if (macho_info->flags & MACHO_INFO_DEBUG_HEADER) 00950 { 00951 static void* dyld_all_image_infos_addr; 00952 00953 /* This symbol should be in the same place in all processes. */ 00954 if (!dyld_all_image_infos_addr) 00955 { 00956 struct nlist nl[2]; 00957 memset(nl, 0, sizeof(nl)); 00958 nl[0].n_un.n_name = (char*)"_dyld_all_image_infos"; 00959 if (!nlist("/usr/lib/dyld", nl)) 00960 dyld_all_image_infos_addr = (void*)nl[0].n_value; 00961 } 00962 00963 if (dyld_all_image_infos_addr) 00964 macho_info->dbg_hdr_addr = (unsigned long)dyld_all_image_infos_addr; 00965 else 00966 ret = FALSE; 00967 TRACE("dbg_hdr_addr = 0x%08lx\n", macho_info->dbg_hdr_addr); 00968 } 00969 00970 if (macho_info->flags & MACHO_INFO_MODULE) 00971 { 00972 struct macho_module_info *macho_module_info; 00973 struct module_format* modfmt = 00974 HeapAlloc(GetProcessHeap(), 0, sizeof(struct module_format) + sizeof(struct macho_module_info)); 00975 if (!modfmt) goto leave; 00976 macho_info->module = module_new(pcs, filename, DMT_MACHO, FALSE, load_addr, 00977 fmap.segs_size, 0, calc_crc32(fmap.fd)); 00978 if (!macho_info->module) 00979 { 00980 HeapFree(GetProcessHeap(), 0, modfmt); 00981 goto leave; 00982 } 00983 macho_module_info = (void*)(modfmt + 1); 00984 macho_info->module->format_info[DFI_MACHO] = modfmt; 00985 00986 modfmt->module = macho_info->module; 00987 modfmt->remove = NULL; 00988 modfmt->loc_compute = NULL; 00989 modfmt->u.macho_info = macho_module_info; 00990 00991 macho_module_info->load_addr = load_addr; 00992 00993 if (dbghelp_options & SYMOPT_DEFERRED_LOADS) 00994 macho_info->module->module.SymType = SymDeferred; 00995 else if (!macho_load_debug_info(macho_info->module, &fmap)) 00996 ret = FALSE; 00997 00998 macho_info->module->format_info[DFI_MACHO]->u.macho_info->in_use = 1; 00999 macho_info->module->format_info[DFI_MACHO]->u.macho_info->is_loader = 0; 01000 TRACE("module = %p\n", macho_info->module); 01001 } 01002 01003 if (macho_info->flags & MACHO_INFO_NAME) 01004 { 01005 WCHAR* ptr; 01006 ptr = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(filename) + 1) * sizeof(WCHAR)); 01007 if (ptr) 01008 { 01009 strcpyW(ptr, filename); 01010 macho_info->module_name = ptr; 01011 } 01012 else ret = FALSE; 01013 TRACE("module_name = %p %s\n", macho_info->module_name, debugstr_w(macho_info->module_name)); 01014 } 01015 leave: 01016 macho_unmap_file(&fmap); 01017 01018 TRACE(" => %d\n", ret); 01019 return ret; 01020 } 01021 01022 /****************************************************************** 01023 * macho_load_file_from_path 01024 * Tries to load a Mach-O file from a set of paths (separated by ':') 01025 */ 01026 static BOOL macho_load_file_from_path(HANDLE hProcess, 01027 const WCHAR* filename, 01028 unsigned long load_addr, 01029 const char* path, 01030 struct macho_info* macho_info) 01031 { 01032 BOOL ret = FALSE; 01033 WCHAR *s, *t, *fn; 01034 WCHAR* pathW = NULL; 01035 unsigned len; 01036 01037 TRACE("(%p, %s, 0x%08lx, %s, %p)\n", hProcess, debugstr_w(filename), load_addr, 01038 debugstr_a(path), macho_info); 01039 01040 if (!path) return FALSE; 01041 01042 len = MultiByteToWideChar(CP_UNIXCP, 0, path, -1, NULL, 0); 01043 pathW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); 01044 if (!pathW) return FALSE; 01045 MultiByteToWideChar(CP_UNIXCP, 0, path, -1, pathW, len); 01046 01047 for (s = pathW; s && *s; s = (t) ? (t+1) : NULL) 01048 { 01049 t = strchrW(s, ':'); 01050 if (t) *t = '\0'; 01051 fn = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(filename) + 1 + lstrlenW(s) + 1) * sizeof(WCHAR)); 01052 if (!fn) break; 01053 strcpyW(fn, s); 01054 strcatW(fn, S_SlashW); 01055 strcatW(fn, filename); 01056 ret = macho_load_file(hProcess, fn, load_addr, macho_info); 01057 HeapFree(GetProcessHeap(), 0, fn); 01058 if (ret) break; 01059 s = (t) ? (t+1) : NULL; 01060 } 01061 01062 TRACE(" => %d\n", ret); 01063 HeapFree(GetProcessHeap(), 0, pathW); 01064 return ret; 01065 } 01066 01067 /****************************************************************** 01068 * macho_load_file_from_dll_path 01069 * 01070 * Tries to load a Mach-O file from the dll path 01071 */ 01072 static BOOL macho_load_file_from_dll_path(HANDLE hProcess, 01073 const WCHAR* filename, 01074 unsigned long load_addr, 01075 struct macho_info* macho_info) 01076 { 01077 BOOL ret = FALSE; 01078 unsigned int index = 0; 01079 const char *path; 01080 01081 TRACE("(%p, %s, 0x%08lx, %p)\n", hProcess, debugstr_w(filename), load_addr, 01082 macho_info); 01083 01084 while (!ret && (path = wine_dll_enum_load_path( index++ ))) 01085 { 01086 WCHAR *name; 01087 unsigned len; 01088 01089 len = MultiByteToWideChar(CP_UNIXCP, 0, path, -1, NULL, 0); 01090 01091 name = HeapAlloc( GetProcessHeap(), 0, 01092 (len + lstrlenW(filename) + 2) * sizeof(WCHAR) ); 01093 01094 if (!name) break; 01095 MultiByteToWideChar(CP_UNIXCP, 0, path, -1, name, len); 01096 strcatW( name, S_SlashW ); 01097 strcatW( name, filename ); 01098 ret = macho_load_file(hProcess, name, load_addr, macho_info); 01099 HeapFree( GetProcessHeap(), 0, name ); 01100 } 01101 TRACE(" => %d\n", ret); 01102 return ret; 01103 } 01104 01105 /****************************************************************** 01106 * macho_search_and_load_file 01107 * 01108 * Lookup a file in standard Mach-O locations, and if found, load it 01109 */ 01110 static BOOL macho_search_and_load_file(struct process* pcs, const WCHAR* filename, 01111 unsigned long load_addr, 01112 struct macho_info* macho_info) 01113 { 01114 BOOL ret = FALSE; 01115 struct module* module; 01116 static WCHAR S_libstdcPPW[] = {'l','i','b','s','t','d','c','+','+','\0'}; 01117 const WCHAR* p; 01118 01119 TRACE("(%p/%p, %s, 0x%08lx, %p)\n", pcs, pcs->handle, debugstr_w(filename), load_addr, 01120 macho_info); 01121 01122 if (filename == NULL || *filename == '\0') return FALSE; 01123 if ((module = module_is_already_loaded(pcs, filename))) 01124 { 01125 macho_info->module = module; 01126 module->format_info[DFI_MACHO]->u.macho_info->in_use = 1; 01127 return module->module.SymType; 01128 } 01129 01130 if (strstrW(filename, S_libstdcPPW)) return FALSE; /* We know we can't do it */ 01131 01132 /* If has no directories, try LD_LIBRARY_PATH first. */ 01133 if (!strchrW(filename, '/')) 01134 { 01135 ret = macho_load_file_from_path(pcs, filename, load_addr, 01136 getenv("PATH"), macho_info); 01137 } 01138 /* Try DYLD_LIBRARY_PATH, with just the filename (no directories). */ 01139 if (!ret) 01140 { 01141 if ((p = strrchrW(filename, '/'))) p++; 01142 else p = filename; 01143 ret = macho_load_file_from_path(pcs, p, load_addr, 01144 getenv("DYLD_LIBRARY_PATH"), macho_info); 01145 } 01146 /* Try the path as given. */ 01147 if (!ret) 01148 ret = macho_load_file(pcs, filename, load_addr, macho_info); 01149 /* Try DYLD_FALLBACK_LIBRARY_PATH, with just the filename (no directories). */ 01150 if (!ret) 01151 { 01152 ret = macho_load_file_from_path(pcs, p, load_addr, 01153 getenv("DYLD_FALLBACK_LIBRARY_PATH"), macho_info); 01154 } 01155 if (!ret && !strchrW(filename, '/')) 01156 ret = macho_load_file_from_dll_path(pcs, filename, load_addr, macho_info); 01157 01158 return ret; 01159 } 01160 01161 /****************************************************************** 01162 * macho_enum_modules_internal 01163 * 01164 * Enumerate Mach-O modules from a running process 01165 */ 01166 static BOOL macho_enum_modules_internal(const struct process* pcs, 01167 const WCHAR* main_name, 01168 enum_modules_cb cb, void* user) 01169 { 01170 struct dyld_all_image_infos image_infos; 01171 struct dyld_image_info* info_array = NULL; 01172 unsigned long len; 01173 int i; 01174 char bufstr[256]; 01175 WCHAR bufstrW[MAX_PATH]; 01176 BOOL ret = FALSE; 01177 01178 TRACE("(%p/%p, %s, %p, %p)\n", pcs, pcs->handle, debugstr_w(main_name), cb, 01179 user); 01180 01181 if (!pcs->dbg_hdr_addr || 01182 !ReadProcessMemory(pcs->handle, (void*)pcs->dbg_hdr_addr, 01183 &image_infos, sizeof(image_infos), NULL) || 01184 !image_infos.infoArray) 01185 goto done; 01186 TRACE("Process has %u image infos at %p\n", image_infos.infoArrayCount, image_infos.infoArray); 01187 01188 len = image_infos.infoArrayCount * sizeof(info_array[0]); 01189 info_array = HeapAlloc(GetProcessHeap(), 0, len); 01190 if (!info_array || 01191 !ReadProcessMemory(pcs->handle, image_infos.infoArray, 01192 info_array, len, NULL)) 01193 goto done; 01194 TRACE("... read image infos\n"); 01195 01196 for (i = 0; i < image_infos.infoArrayCount; i++) 01197 { 01198 if (info_array[i].imageFilePath != NULL && 01199 ReadProcessMemory(pcs->handle, info_array[i].imageFilePath, bufstr, sizeof(bufstr), NULL)) 01200 { 01201 bufstr[sizeof(bufstr) - 1] = '\0'; 01202 TRACE("[%d] image file %s\n", i, debugstr_a(bufstr)); 01203 MultiByteToWideChar(CP_UNIXCP, 0, bufstr, -1, bufstrW, sizeof(bufstrW) / sizeof(WCHAR)); 01204 if (main_name && !bufstrW[0]) strcpyW(bufstrW, main_name); 01205 if (!cb(bufstrW, (unsigned long)info_array[i].imageLoadAddress, user)) break; 01206 } 01207 } 01208 01209 ret = TRUE; 01210 done: 01211 HeapFree(GetProcessHeap(), 0, info_array); 01212 return ret; 01213 } 01214 01215 struct macho_sync 01216 { 01217 struct process* pcs; 01218 struct macho_info macho_info; 01219 }; 01220 01221 static BOOL macho_enum_sync_cb(const WCHAR* name, unsigned long addr, void* user) 01222 { 01223 struct macho_sync* ms = user; 01224 01225 TRACE("(%s, 0x%08lx, %p)\n", debugstr_w(name), addr, user); 01226 macho_search_and_load_file(ms->pcs, name, addr, &ms->macho_info); 01227 return TRUE; 01228 } 01229 01230 /****************************************************************** 01231 * macho_synchronize_module_list 01232 * 01233 * Rescans the debuggee's modules list and synchronizes it with 01234 * the one from 'pcs', ie: 01235 * - if a module is in debuggee and not in pcs, it's loaded into pcs 01236 * - if a module is in pcs and not in debuggee, it's unloaded from pcs 01237 */ 01238 BOOL macho_synchronize_module_list(struct process* pcs) 01239 { 01240 struct module* module; 01241 struct macho_sync ms; 01242 01243 TRACE("(%p/%p)\n", pcs, pcs->handle); 01244 01245 for (module = pcs->lmodules; module; module = module->next) 01246 { 01247 if (module->type == DMT_MACHO && !module->is_virtual) 01248 module->format_info[DFI_MACHO]->u.macho_info->in_use = 0; 01249 } 01250 01251 ms.pcs = pcs; 01252 ms.macho_info.flags = MACHO_INFO_MODULE; 01253 if (!macho_enum_modules_internal(pcs, NULL, macho_enum_sync_cb, &ms)) 01254 return FALSE; 01255 01256 module = pcs->lmodules; 01257 while (module) 01258 { 01259 if (module->type == DMT_MACHO && !module->is_virtual && 01260 !module->format_info[DFI_MACHO]->u.macho_info->in_use && 01261 !module->format_info[DFI_MACHO]->u.macho_info->is_loader) 01262 { 01263 module_remove(pcs, module); 01264 /* restart all over */ 01265 module = pcs->lmodules; 01266 } 01267 else module = module->next; 01268 } 01269 return TRUE; 01270 } 01271 01272 /****************************************************************** 01273 * macho_search_loader 01274 * 01275 * Lookup in a running Mach-O process the loader, and sets its Mach-O link 01276 * address (for accessing the list of loaded images) in pcs. 01277 * If flags is MACHO_INFO_MODULE, the module for the loader is also 01278 * added as a module into pcs. 01279 */ 01280 static BOOL macho_search_loader(struct process* pcs, struct macho_info* macho_info) 01281 { 01282 return macho_search_and_load_file(pcs, get_wine_loader_name(), 0, macho_info); 01283 } 01284 01285 /****************************************************************** 01286 * macho_read_wine_loader_dbg_info 01287 * 01288 * Try to find a decent wine executable which could have loaded the debuggee 01289 */ 01290 BOOL macho_read_wine_loader_dbg_info(struct process* pcs) 01291 { 01292 struct macho_info macho_info; 01293 01294 TRACE("(%p/%p)\n", pcs, pcs->handle); 01295 macho_info.flags = MACHO_INFO_DEBUG_HEADER | MACHO_INFO_MODULE; 01296 if (!macho_search_loader(pcs, &macho_info)) return FALSE; 01297 macho_info.module->format_info[DFI_MACHO]->u.macho_info->is_loader = 1; 01298 module_set_module(macho_info.module, S_WineLoaderW); 01299 return (pcs->dbg_hdr_addr = macho_info.dbg_hdr_addr) != 0; 01300 } 01301 01302 /****************************************************************** 01303 * macho_enum_modules 01304 * 01305 * Enumerates the Mach-O loaded modules from a running target (hProc) 01306 * This function doesn't require that someone has called SymInitialize 01307 * on this very process. 01308 */ 01309 BOOL macho_enum_modules(HANDLE hProc, enum_modules_cb cb, void* user) 01310 { 01311 struct process pcs; 01312 struct macho_info macho_info; 01313 BOOL ret; 01314 01315 TRACE("(%p, %p, %p)\n", hProc, cb, user); 01316 memset(&pcs, 0, sizeof(pcs)); 01317 pcs.handle = hProc; 01318 macho_info.flags = MACHO_INFO_DEBUG_HEADER | MACHO_INFO_NAME; 01319 if (!macho_search_loader(&pcs, &macho_info)) return FALSE; 01320 pcs.dbg_hdr_addr = macho_info.dbg_hdr_addr; 01321 ret = macho_enum_modules_internal(&pcs, macho_info.module_name, cb, user); 01322 HeapFree(GetProcessHeap(), 0, (char*)macho_info.module_name); 01323 return ret; 01324 } 01325 01326 struct macho_load 01327 { 01328 struct process* pcs; 01329 struct macho_info macho_info; 01330 const WCHAR* name; 01331 BOOL ret; 01332 }; 01333 01334 /****************************************************************** 01335 * macho_load_cb 01336 * 01337 * Callback for macho_load_module, used to walk the list of loaded 01338 * modules. 01339 */ 01340 static BOOL macho_load_cb(const WCHAR* name, unsigned long addr, void* user) 01341 { 01342 struct macho_load* ml = user; 01343 const WCHAR* p; 01344 01345 TRACE("(%s, 0x%08lx, %p)\n", debugstr_w(name), addr, user); 01346 01347 /* memcmp is needed for matches when bufstr contains also version information 01348 * ml->name: libc.so, name: libc.so.6.0 01349 */ 01350 p = strrchrW(name, '/'); 01351 if (!p++) p = name; 01352 if (!memcmp(p, ml->name, lstrlenW(ml->name) * sizeof(WCHAR))) 01353 { 01354 ml->ret = macho_search_and_load_file(ml->pcs, name, addr, &ml->macho_info); 01355 return FALSE; 01356 } 01357 return TRUE; 01358 } 01359 01360 /****************************************************************** 01361 * macho_load_module 01362 * 01363 * Loads a Mach-O module and stores it in process' module list. 01364 * Also, find module real name and load address from 01365 * the real loaded modules list in pcs address space. 01366 */ 01367 struct module* macho_load_module(struct process* pcs, const WCHAR* name, unsigned long addr) 01368 { 01369 struct macho_load ml; 01370 01371 TRACE("(%p/%p, %s, 0x%08lx)\n", pcs, pcs->handle, debugstr_w(name), addr); 01372 01373 ml.macho_info.flags = MACHO_INFO_MODULE; 01374 ml.ret = FALSE; 01375 01376 if (pcs->dbg_hdr_addr) /* we're debugging a live target */ 01377 { 01378 ml.pcs = pcs; 01379 /* do only the lookup from the filename, not the path (as we lookup module 01380 * name in the process' loaded module list) 01381 */ 01382 ml.name = strrchrW(name, '/'); 01383 if (!ml.name++) ml.name = name; 01384 ml.ret = FALSE; 01385 01386 if (!macho_enum_modules_internal(pcs, NULL, macho_load_cb, &ml)) 01387 return NULL; 01388 } 01389 else if (addr) 01390 { 01391 ml.name = name; 01392 ml.ret = macho_search_and_load_file(pcs, ml.name, addr, &ml.macho_info); 01393 } 01394 if (!ml.ret) return NULL; 01395 assert(ml.macho_info.module); 01396 return ml.macho_info.module; 01397 } 01398 01399 #else /* HAVE_MACH_O_LOADER_H */ 01400 01401 BOOL macho_synchronize_module_list(struct process* pcs) 01402 { 01403 return FALSE; 01404 } 01405 01406 BOOL macho_fetch_file_info(const WCHAR* name, DWORD_PTR* base, 01407 DWORD* size, DWORD* checksum) 01408 { 01409 return FALSE; 01410 } 01411 01412 BOOL macho_read_wine_loader_dbg_info(struct process* pcs) 01413 { 01414 return FALSE; 01415 } 01416 01417 BOOL macho_enum_modules(HANDLE hProc, enum_modules_cb cb, void* user) 01418 { 01419 return FALSE; 01420 } 01421 01422 struct module* macho_load_module(struct process* pcs, const WCHAR* name, unsigned long addr) 01423 { 01424 return NULL; 01425 } 01426 01427 BOOL macho_load_debug_info(struct module* module, struct macho_file_map* fmap) 01428 { 01429 return FALSE; 01430 } 01431 #endif /* HAVE_MACH_O_LOADER_H */ Generated on Sun May 27 2012 04:23:22 for ReactOS by
1.7.6.1
|