ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

macho_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 doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.