Changeset 2861


Ignore:
Timestamp:
Nov 10, 2006, 4:04:42 AM (19 years ago)
Author:
bird
Message:

Put the PE module interpreter thru the wringer and learnt how much the window file mapping API sucks.

Location:
trunk/kLdr
Files:
9 edited

Legend:

Unmodified
Added
Removed
  • trunk/kLdr/Makefile.kmk

    r2859 r2861  
    4141 TEMPLATE_TST_ASFLAGS = -f win
    4242 TEMPLATE_TST_DEFS = __WIN__
    43  TEMPLATE_TST_SDKS = WIN32SDK
    44  #kLdr_SDKS.x86 = WIN32SDK
    45  #kLdr_SDKS.amd64 = WIN64SDK
     43 TEMPLATE_TST_SDKS = WIN32SDK W2K3DDKX86
     44 #TEMPLATE_SDKS.x86 = WIN32SDK W2K3DDKX86
     45 #TEMPLATE_SDKS.amd64 = WIN64SDK W2K3DDKAMD64
    4646
    4747## @todo this is a kBuild bug!
     
    7777 kLdr_LDFLAGS = -Entry:DllMain@12 -Debug
    7878 kLdr_DEFS = __WIN__
    79  kLdr_SDKS = WIN32SDK
    80  #kLdr_SDKS.x86 = WIN32SDK
    81  #kLdr_SDKS.amd64 = WIN64SDK
     79 # crap, this doesn't work right either:
     80 #kLdr_SDKS = WIN32SDK W2K3DDKX86
     81 kLdr_SDKS = W2K3DDKX86 WIN32SDK
     82 #kLdr_SDKS.x86 = WIN32SDK W2K3DDKX86
     83 #kLdr_SDKS.amd64 = WIN64SDK W2K3DDKAMD64
    8284 kLdr_LIBS = \
    83         $$(PATH_TOOL_VCC70_LIB)/LIBC.lib
     85        $$(PATH_TOOL_VCC70_LIB)/LIBC.lib \
     86        $(PATH_SDK_W2K3DDKX86_LIB)/ntdll.lib
    8487else
    8588 ifneq ($(filter os2,$(BUILD_TARGET)),)
  • trunk/kLdr/kLdr-win.def

    r2858 r2861  
    3939    kLdrRdrName
    4040    kLdrRdrPageSize
    41     kLdrRdrPrepare
    4241    kLdrRdrMap
    43     kLdrRdrRefreshMap
     42    kLdrRdrRefresh
    4443    kLdrRdrProtect
    4544    kLdrRdrUnmap
    46     kLdrRdrUnprepare
    4745    kLdrRdrDone
    4846
  • trunk/kLdr/kLdr.h

    r2859 r2861  
    8787# define PRI_KLDRSIZE    "llx"
    8888#endif
     89
     90/** Pointer to a loader segment. */
     91typedef struct KLDRSEG *PKLDRSEG;
     92/** Pointer to a loader segment. */
     93typedef const struct KLDRSEG *PCKLDRSEG;
     94
    8995
    9096
     
    167173    /** @copydoc kLdrRdrPageSize */
    168174    size_t  (* pfnPageSize)(PKLDRRDR pRdr);
    169     /** @copydoc kLdrRdrPrepare */
    170     int     (* pfnPrepare)(PKLDRRDR pRdr, void **ppv, size_t cb, unsigned fFixed);
    171175    /** @copydoc kLdrRdrMap */
    172     int     (* pfnMap)(PKLDRRDR pRdr, void *pv, size_t cb, KLDRPROT enmProt, off_t offFile, size_t cbFile);
    173     /** @copydoc kLdrRdrRefreshMap */
    174     int     (* pfnRefreshMap)(PKLDRRDR pRdr, void *pv, size_t cb, KLDRPROT enmProt, off_t offFile, size_t cbFile);
     176    int     (* pfnMap)(     PKLDRRDR pRdr, void **ppvBase, uint32_t cSegments, PCKLDRSEG paSegments, unsigned fFixed);
     177    /** @copydoc kLdrRdrRefresh */
     178    int     (* pfnRefresh)( PKLDRRDR pRdr, void *pvBase, uint32_t cSegments, PCKLDRSEG paSegments);
    175179    /** @copydoc kLdrRdrProtect */
    176     int     (* pfnProtect)(PKLDRRDR pRdr, void *pv, size_t cb, KLDRPROT enmProt);
     180    int     (* pfnProtect)( PKLDRRDR pRdr, void *pvBase, uint32_t cSegments, PCKLDRSEG paSegments, unsigned fUnprotectOrProtect);
    177181    /** @copydoc kLdrRdrUnmap */
    178     int     (* pfnUnmap)(PKLDRRDR pRdr, void *pv, size_t cb);
    179     /** @copydoc kLdrRdrUnprepare */
    180     int     (* pfnUnprepare)(PKLDRRDR pRdr, void *pv, size_t cb);
     182    int     (* pfnUnmap)(   PKLDRRDR pRdr, void *pvBase, uint32_t cSegments, PCKLDRSEG paSegments);
    181183    /** @copydoc kLdrRdrDone */
    182     void    (* pfnDone)(PKLDRRDR pRdr);
     184    void    (* pfnDone)(    PKLDRRDR pRdr);
    183185    /** The usual non-zero dummy that makes sure we've initialized all members. */
    184186    uint32_t u32Dummy;
     
    215217const char *kLdrRdrName(PKLDRRDR pRdr);
    216218size_t  kLdrRdrPageSize(PKLDRRDR pRdr);
    217 int     kLdrRdrPrepare( PKLDRRDR pRdr, void **ppv, size_t cb, unsigned fFixed);
    218 int     kLdrRdrMap(     PKLDRRDR pRdr, void *pv, size_t cb, KLDRPROT enmProt, off_t offFile, size_t cbFile);
    219 int     kLdrRdrRefreshMap(PKLDRRDR pRdr, void *pv, size_t cb, KLDRPROT enmProt, off_t offFile, size_t cbFile);
    220 int     kLdrRdrProtect( PKLDRRDR pRdr, void *pv, size_t cb, KLDRPROT enmProt);
    221 int     kLdrRdrUnmap(   PKLDRRDR pRdr, void *pv, size_t cb);
    222 int     kLdrRdrUnprepare(PKLDRRDR pRdr, void *pv, size_t cb);
     219int     kLdrRdrMap(     PKLDRRDR pRdr, void **ppvBase, uint32_t cSegments, PCKLDRSEG paSegments, unsigned fFixed);
     220int     kLdrRdrRefresh( PKLDRRDR pRdr, void *pvBase, uint32_t cSegments, PCKLDRSEG paSegments);
     221int     kLdrRdrProtect( PKLDRRDR pRdr, void *pvBase, uint32_t cSegments, PCKLDRSEG paSegments, unsigned fUnprotectOrProtect);
     222int     kLdrRdrUnmap(   PKLDRRDR pRdr, void *pvBase, uint32_t cSegments, PCKLDRSEG paSegments);
    223223void    kLdrRdrDone(    PKLDRRDR pRdr);
    224224
     
    430430    uintptr_t       MapAddress;
    431431} KLDRSEG;
    432 /** Pointer to a loader segment. */
    433 typedef KLDRSEG *PKLDRSEG;
    434 /** Pointer to a loader segment. */
    435 typedef const KLDRSEG *PCKLDRSEG;
    436432
    437433
     
    10291025/** Thread attach failed. */
    10301026#define KLDR_ERR_THREAD_ATTACH_FAILED                       (KLDR_ERR_BASE + 57)
     1027/** The file reader can't take more concurrent mappings. */
     1028#define KLDR_ERR_TOO_MANY_MAPPINGS                          (KLDR_ERR_BASE + 58)
    10311029
    10321030
  • trunk/kLdr/kLdrHlp.c

    r2854 r2861  
    241241
    242242    *ppv = VirtualAlloc(fFixed ? *ppv : NULL, cb, MEM_COMMIT, fProt);
    243     if (*ppv == NULL)
    244     {
    245         rc = GetLastError();
    246         kldrHlpAssert(0);
    247     }
     243    if (*ppv != NULL)
     244        return 0;
     245    rc = GetLastError();
     246    kldrHlpAssert(0);
    248247    return rc;
    249248
  • trunk/kLdr/kLdrHlp.h

    r2858 r2861  
    3434
    3535/** Get the minimum of two values. */
    36 #define KLDR_MIN(a, b) ((a) <= (b) ? (a) : (b))
     36#define KLDR_MIN(a, b)              ((a) <= (b) ? (a) : (b))
    3737/** Get the maximum of two values. */
    38 #define KLDR_MAX(a, b) ((a) >= (b) ? (a) : (b))
     38#define KLDR_MAX(a, b)              ((a) >= (b) ? (a) : (b))
    3939/** Calculate the offset of a structure member. */
    4040#define KLDR_OFFSETOF(strct, memb)  ( (size_t)( &((strct *)0)->memb ) )
     
    4343/** Align a void * value. */
    4444#define KLDR_ALIGN_P(pv, align)     ( (void *)( ((uintptr_t)(pv) + ((align) - 1)) & ~(uintptr_t)((align) - 1) ) )
     45/** Number of elements in an array. */
     46#define KLDR_ELEMENTS(a)            ( sizeof(a) / sizeof((a)[0]) )
     47
    4548/** @def KLDRHLP_LE2H_U16
    4649 * Unsigned 16-bit little-endian to host translation. */
  • trunk/kLdr/kLdrModPE.c

    r2860 r2861  
    113113static int  kldrModPEDoForwarderQuery(PKLDRMODPE pModPE, const void *pvBits, const char *pszForwarder,
    114114                                     PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser, PKLDRADDR puValue, uint32_t *pfKind);
    115 static int  kldrModPEUnprotect(PKLDRMODPE pModPE, const void *pvMapping);
    116 static int  kldrModPEProtect(PKLDRMODPE pModPE, const void *pvMapping);
    117115static int  kldrModPEDoFixups(PKLDRMODPE pModPE, void *pvMapping, KLDRADDR NewBaseAddress, KLDRADDR OldBaseAddress);
    118116static int  kldrModPEDoImports32Bit(PKLDRMODPE pModPE, void *pvMapping, const IMAGE_IMPORT_DESCRIPTOR *pImpDesc,
     
    554552    unsigned    fFixed;
    555553    void       *pvBase;
    556     size_t      cb;
    557554    int         rc;
    558555    uint32_t    i;
    559556
    560557    /*
    561      * Prepare it.
    562      */
    563     /* size */
    564     cb = (size_t)pMod->pOps->pfnSize(pModPE->pMod);
    565     if (cb != pMod->pOps->pfnSize(pModPE->pMod))
    566         return KLDR_ERR_ADDRESS_OVERFLOW;
    567 
     558     * Map it.
     559     */
    568560    /* fixed image? */
    569561    fFixed = fForReal
     
    580572
    581573    /* try do the prepare */
    582     rc = kLdrRdrPrepare(pMod->pRdr, &pvBase, cb, fFixed);
     574    rc = kLdrRdrMap(pMod->pRdr, &pvBase, pMod->cSegments, pMod->aSegments, fFixed);
    583575    if (rc)
    584576        return rc;
    585577
    586578    /*
    587      * Map the segments (sub sections in PE terms).
    588      */
    589     for (i = 0; i < pMod->cSegments; i++)
    590     {
    591         void *pvSeg;
    592 
    593         if (!pMod->aSegments[i].Alignment)
    594             continue;
    595 
    596         pvSeg = (uint8_t *)pvBase + pMod->aSegments[i].RVA;
    597         rc = kLdrRdrMap(pMod->pRdr, pvSeg, pMod->aSegments[i].cbMapped, pMod->aSegments[i].enmProt,
    598                         pMod->aSegments[i].offFile, pMod->aSegments[i].cbFile);
    599         if (rc)
     579     * Update the segments with their map addresses.
     580     */
     581    if (fForReal)
     582    {
     583        for (i = 0; i < pMod->cSegments; i++)
    600584        {
    601             /* bailout */
    602             while (i-- > 0)
    603             {
    604                 if (!pMod->aSegments[i].Alignment)
    605                     continue;
    606 
    607                 kLdrRdrUnmap(pMod->pRdr, (void *)pMod->aSegments[i].MapAddress, pMod->aSegments[i].cbMapped);
    608                 pMod->aSegments[i].MapAddress = 0;
    609             }
    610             break;
     585            if (pMod->aSegments[i].RVA != NIL_KLDRADDR)
     586                pMod->aSegments[i].MapAddress = (uintptr_t)pvBase + (uintptr_t)pMod->aSegments[i].RVA;
    611587        }
    612         pMod->aSegments[i].MapAddress = (uintptr_t)pvSeg;
    613     }
    614 
    615     if (!rc)
    616     {
    617         if (fForReal)
    618             pModPE->pvMapping = pvBase;
    619         else
    620             pModPE->pvBits = pvBase;
     588        pModPE->pvMapping = pvBase;
    621589    }
    622590    else
    623         kLdrRdrUnprepare(pMod->pRdr, pvBase, cb);
    624     return rc;
     591        pModPE->pvBits = pvBase;
     592    return 0;
    625593}
    626594
     
    640608    PKLDRMOD    pMod = pModPE->pMod;
    641609    size_t      cb = (size_t)pMod->pOps->pfnSize(pModPE->pMod);
    642     int         rc2;
    643     int         rc = 0;
     610    int         rc;
    644611    uint32_t    i;
    645612
    646613    /*
    647      * Unmap the segments (sub sections in PE terms).
    648      */
    649     for (i = 0; i < pMod->cSegments; i++)
    650     {
    651         if (!pMod->aSegments[i].MapAddress)
    652             continue;
    653 
    654         rc2 = kLdrRdrUnmap(pMod->pRdr, (void *)pMod->aSegments[i].MapAddress, pMod->aSegments[i].cbMapped);
    655         if (!rc2)
     614     * Try unmap the image.
     615     */
     616    rc = kLdrRdrUnmap(pMod->pRdr, (void *)pvMapping, pMod->cSegments, pMod->aSegments);
     617    if (rc)
     618        return rc;
     619
     620    /*
     621     * Update the segments to reflect that they aren't mapped any longer.
     622     */
     623    if (pModPE->pvMapping == pvMapping)
     624    {
     625        pModPE->pvMapping = NULL;
     626        for (i = 0; i < pMod->cSegments; i++)
    656627            pMod->aSegments[i].MapAddress = 0;
    657         else if (!rc)
    658             rc = rc2;
    659     }
    660 
    661     /*
    662      * 'Unprepare' the mapping region.
    663      */
    664     if (!rc)
    665     {
    666         rc = kLdrRdrUnprepare(pMod->pRdr, (void *)pvMapping, cb);
    667         if (!rc)
    668         {
    669             if (pModPE->pvBits == pvMapping)
    670                 pModPE->pvBits = NULL;
    671             if (pModPE->pvMapping == pvMapping)
    672                 pModPE->pvMapping = NULL;
    673         }
    674     }
    675 
    676     return rc;
     628    }
     629    if (pModPE->pvBits == pvMapping)
     630        pModPE->pvBits = NULL;
     631
     632    return 0;
    677633}
    678634
     
    717673        else
    718674        {
    719             /** @todo do an internal mapping. */
    720             rc = -1;
     675            /* create an internal mapping. */
     676            rc = kldrModPEDoMap(pModPE, 0 /* not for real */);
     677            if (rc)
     678                return rc;
     679            KLDRMODPE_ASSERT(pModPE->pvBits);
     680            *ppvBits = pModPE->pvBits;
    721681        }
    722682    }
     
    13361296static int kldrModPEReload(PKLDRMOD pMod)
    13371297{
    1338     PKLDRMODPE      pModPE = (PKLDRMODPE)pMod->pvData;
    1339     uint32_t        i;
    1340     int             rc;
    1341     const size_t    cbPage = kLdrRdrPageSize(pMod->pRdr);
     1298    PKLDRMODPE pModPE = (PKLDRMODPE)pMod->pvData;
    13421299
    13431300    /*
     
    13471304        return KLDR_ERR_NOT_MAPPED;
    13481305
    1349     /*
    1350      * Iterate the objects and ask the file provider to undo all the changes.
    1351      */
    1352     for (i = rc = 0; !rc && i < pMod->cSegments; i++)
    1353         rc = kLdrRdrRefreshMap(pMod->pRdr,
    1354                                (void *)pMod->aSegments[i].MapAddress,
    1355                                (size_t)pMod->aSegments[i].cb,
    1356                                pMod->aSegments[i].enmProt,
    1357                                pMod->aSegments[i].offFile,
    1358                                pMod->aSegments[i].cbFile);
    1359     return rc;
     1306    /* the file provider does it all */
     1307    return kLdrRdrRefresh(pMod->pRdr, (void *)pModPE->pvMapping, pMod->cSegments, pMod->aSegments);
    13601308}
    13611309
     
    13761324     * Before doing anything we'll have to make all pages writable.
    13771325     */
    1378     rc = kldrModPEUnprotect(pModPE, pModPE->pvMapping);
     1326    rc = kLdrRdrProtect(pMod->pRdr, (void *)pModPE->pvMapping, pMod->cSegments, pMod->aSegments, 1 /* unprotect */);
    13791327    if (rc)
    13801328        return rc;
     
    13951343     * Restore protection.
    13961344     */
    1397     rc2 = kldrModPEProtect(pModPE, pModPE->pvMapping);
     1345    rc2 = kLdrRdrProtect(pMod->pRdr, (void *)pModPE->pvMapping, pMod->cSegments, pMod->aSegments, 0 /* protect */);
    13981346    if (!rc && rc2)
    13991347        rc = rc2;
    1400     return rc;
    1401 }
    1402 
    1403 
    1404 /**
    1405  * Make all segment writable so we can apply fixups and setup imports.
    1406  *
    1407  * @returns 0 on success, non-zero kLdrRdrProtect() status code on failure.
    1408  * @param   pModPE          The PE module interpreter instance.
    1409  * @param   pvMapping       The base mapping to unprotect.
    1410  */
    1411 static int  kldrModPEUnprotect(PKLDRMODPE pModPE, const void *pvMapping)
    1412 {
    1413     PKLDRMOD    pMod = pModPE->pMod;
    1414     int         rc;
    1415     uint32_t    i;
    1416 
    1417     /*
    1418      * Iterate the segments.
    1419      */
    1420     for (i = rc = 0; !rc && i < pMod->cSegments; i++)
    1421     {
    1422         KLDRPROT enmProt;
    1423 
    1424         /* Skip segments that aren't mapped. */
    1425         if (!pMod->aSegments[i].Alignment)
    1426             continue;
    1427 
    1428         /* calc writable protection and skip those which are already writable. */
    1429         enmProt = pMod->aSegments[i].enmProt;
    1430         switch (enmProt)
    1431         {
    1432             case KLDRPROT_NOACCESS:
    1433             case KLDRPROT_READWRITE:
    1434             case KLDRPROT_WRITECOPY:
    1435             case KLDRPROT_EXECUTE_READWRITE:
    1436             case KLDRPROT_EXECUTE_WRITECOPY:
    1437                 continue;
    1438             case KLDRPROT_READONLY:
    1439                 enmProt = KLDRPROT_WRITECOPY;
    1440                 break;
    1441             case KLDRPROT_EXECUTE:
    1442             case KLDRPROT_EXECUTE_READ:
    1443                 enmProt = KLDRPROT_EXECUTE_WRITECOPY;
    1444                 break;
    1445             default:
    1446                 KLDRMODPE_ASSERT(!"invalid");
    1447                 continue;
    1448         }
    1449 
    1450         rc = kLdrRdrProtect(pMod->pRdr,
    1451                             (uint8_t *)pvMapping + (pMod->aSegments[i].LinkAddress - pModPE->Hdrs.OptionalHeader.ImageBase),
    1452                             pMod->aSegments[i].cbMapped,
    1453                             enmProt);
    1454     }
    1455 
    1456     return rc;
    1457 }
    1458 
    1459 
    1460 /**
    1461  * Restore the correct protection for the segments after we're done with fixups and imports.
    1462  *
    1463  * @returns 0 on success, non-zero kLdrRdrProtect() status code on failure.
    1464  * @param   pModPE          The PE module interpreter instance.
    1465  * @param   pvMapping       The base mapping to unprotect.
    1466  */
    1467 static int  kldrModPEProtect(PKLDRMODPE pModPE, const void *pvMapping)
    1468 {
    1469     PKLDRMOD    pMod = pModPE->pMod;
    1470     int         rc;
    1471     uint32_t    i;
    1472 
    1473     /*
    1474      * Iterate the segments.
    1475      */
    1476     for (i = rc = 0; !rc && i < pMod->cSegments; i++)
    1477     {
    1478         KLDRPROT enmProt;
    1479 
    1480         /* Skip segments that aren't mapped. */
    1481         if (!pMod->aSegments[i].Alignment)
    1482             continue;
    1483 
    1484         /* Skip those which are already writable. */
    1485         enmProt = pMod->aSegments[i].enmProt;
    1486         switch (enmProt)
    1487         {
    1488             case KLDRPROT_NOACCESS:
    1489             case KLDRPROT_READWRITE:
    1490             case KLDRPROT_WRITECOPY:
    1491             case KLDRPROT_EXECUTE_READWRITE:
    1492             case KLDRPROT_EXECUTE_WRITECOPY:
    1493                 continue;
    1494             case KLDRPROT_READONLY:
    1495             case KLDRPROT_EXECUTE:
    1496             case KLDRPROT_EXECUTE_READ:
    1497                 break;
    1498             default:
    1499                 KLDRMODPE_ASSERT(!"invalid");
    1500                 continue;
    1501         }
    1502 
    1503         rc = kLdrRdrProtect(pMod->pRdr,
    1504                             (uint8_t *)pvMapping + (pMod->aSegments[i].LinkAddress - pModPE->Hdrs.OptionalHeader.ImageBase),
    1505                             pMod->aSegments[i].cbMapped,
    1506                             enmProt);
    1507     }
    1508 
    15091348    return rc;
    15101349}
  • trunk/kLdr/kLdrRdr.c

    r2856 r2861  
    223223
    224224/**
    225  * Prepares a memory region to map file sections into.
    226  *
    227  * @returns 0 on success, OS specific error code on failure.
    228  * @param   pRdr        The file provider instance.
    229  * @param   ppv         If fFixed is set, *ppv contains the memory location which
    230  *                      the region should be based at. If fFixed is clear the OS
    231  *                      is free to choose the location.
    232  *                      On successful return *ppv contains address of the prepared
    233  *                      memory region.
    234  * @param   cb          The size of the memory region to prepare.
    235  * @param   fFixed      When set *ppv will contain the desired region address.
    236  *
    237  */
    238 int kLdrRdrPrepare(PKLDRRDR pRdr, void **ppv, size_t cb, unsigned fFixed)
    239 {
    240     KLDRRDR_VALIDATE(pRdr);
    241     return pRdr->pOps->pfnPrepare(pRdr, ppv, cb, fFixed);
    242 }
    243 
    244 
    245 /**
    246  * Maps a section of the file into the memory region reserved by pfnPrepare.
    247  *
    248  * @returns 0 on success, OS specific error code on failure.
    249  * @param   pRdr        The file provider instance.
    250  * @param   pv          The address in the prepared region.
    251  * @param   cb          The size of the memory mapping.
    252  * @param   enmProt     The desired memory protection.
    253  * @param   offFile     The start of the raw file bytes.
    254  * @param   cbFile      The number of raw file bytes. This must be less or equal to cb.
    255  */
    256 int kLdrRdrMap(PKLDRRDR pRdr, void *pv, size_t cb, KLDRPROT enmProt, off_t offFile, size_t cbFile)
    257 {
    258     KLDRRDR_VALIDATE(pRdr);
    259     return pRdr->pOps->pfnMap(pRdr, pv, cb, enmProt, offFile, cbFile);
    260 }
    261 
    262 
    263 /**
    264  * Reloads dirty pages in mapped section.
    265  *
    266  * @returns 0 on success, OS specific error code on failure.
    267  * @param   pRdr        The file provider instance.
    268  * @param   pv          The address in the prepared region.
    269  * @param   cb          The size of the memory mapping.
    270  * @param   enmProt     The desired memory protection.
    271  * @param   offFile     The start of the raw file bytes.
    272  * @param   cbFile      The number of raw file bytes. This must be less or equal to cb.
    273  */
    274 int kLdrRdrRefreshMap(PKLDRRDR pRdr, void *pv, size_t cb, KLDRPROT enmProt, off_t offFile, size_t cbFile)
    275 {
    276     KLDRRDR_VALIDATE(pRdr);
    277     return pRdr->pOps->pfnRefreshMap(pRdr, pv, cb, enmProt, offFile, cbFile);
    278 }
    279 
    280 
    281 /**
    282  * Changes the page protection of a section mapped using pfnMap.
    283  *
    284  * This is typically used for applying fixups and similar.
    285  *
    286  * @returns 0 on success, OS specific error code on failure.
    287  * @param   pRdr        The file provider instance.
    288  * @param   pv          The address passed to pfnMap.
    289  * @param   cb          The size passed to pfnMap.
    290  * @param   enmProt     The desired memory protection.
    291  */
    292 int kLdrRdrProtect(PKLDRRDR pRdr, void *pv, size_t cb, KLDRPROT enmProt)
    293 {
    294     KLDRRDR_VALIDATE(pRdr);
    295     return pRdr->pOps->pfnProtect(pRdr, pv, cb, enmProt);
    296 }
    297 
    298 
    299 /**
    300  * Unmaps a section of the file previously mapped using pfnMap.
    301  *
    302  * @returns 0 on success, OS specific error code on failure.
    303  * @param   pRdr        The file provider instance.
    304  * @param   pv          The address passed to pfnMap.
    305  * @param   cb          The size passed to pfnMap.
    306  */
    307 int kLdrRdrUnmap(PKLDRRDR pRdr, void *pv, size_t cb)
    308 {
    309     KLDRRDR_VALIDATE(pRdr);
    310     return pRdr->pOps->pfnUnmap(pRdr, pv, cb);
    311 }
    312 
    313 
    314 /**
    315  * Releases the memory region prepared by pfnPrepare().
    316  *
    317  * Before calling this function, all sections mapped by pfnMap must first be unmapped by calling pfnUnmap.
    318  *
    319  * @returns 0 on success, OS specific error code on failure.
    320  * @param   pRdr        The file provider instance.
    321  * @param   pv          The address of the prepared region.
    322  * @param   cb          The size of the prepared region.
    323  */
    324 int kLdrRdrUnprepare(PKLDRRDR pRdr, void *pv, size_t cb)
    325 {
    326     KLDRRDR_VALIDATE(pRdr);
    327     return pRdr->pOps->pfnUnprepare(pRdr, pv, cb);
     225 * Maps the segments of a image into memory.
     226 *
     227 * The file reader will be using the RVA member of each segment to figure out where
     228 * it goes relative to the image base address.
     229 *
     230 * @returns 0 on success, OS specific error code on failure.
     231 * @param   pRdr        The file provider instance.
     232 * @param   ppvBase     On input when fFixed is set, this contains the base address of the mapping.
     233 *                      On output this contains the base of the image mapping.
     234 * @param   cSegments   The number of segments in the array pointed to by paSegments.
     235 * @param   paSegments  The segments thats going to be mapped.
     236 * @param   fFixed      If set, the address at *ppvBase should be the base address of the mapping.
     237 */
     238int kLdrRdrMap(PKLDRRDR pRdr, void **ppvBase, uint32_t cSegments, PCKLDRSEG paSegments, unsigned fFixed)
     239{
     240    KLDRRDR_VALIDATE(pRdr);
     241    return pRdr->pOps->pfnMap(pRdr, ppvBase, cSegments, paSegments, fFixed);
     242}
     243
     244
     245/**
     246 * Reloads dirty pages in mapped image.
     247 *
     248 * @returns 0 on success, OS specific error code on failure.
     249 * @param   pRdr        The file provider instance.
     250 * @param   pvBase      The base address of the image mapping.
     251 * @param   cSegments   The number of segments in the array pointed to by paSegments.
     252 * @param   paSegments  The segments thats going to be mapped.
     253 */
     254int kLdrRdrRefresh(PKLDRRDR pRdr, void *pvBase, uint32_t cSegments, PCKLDRSEG paSegments)
     255{
     256    KLDRRDR_VALIDATE(pRdr);
     257    return pRdr->pOps->pfnRefresh(pRdr, pvBase, cSegments, paSegments);
     258}
     259
     260
     261/**
     262 * Protects or unprotects an image mapping.
     263 *
     264 * This is typically used for getting write access to read or execute only
     265 * pages while applying fixups.
     266 *
     267 * @returns 0 on success, OS specific error code on failure.
     268 * @param   pRdr        The file provider instance.
     269 * @param   pvBase      The base address of the image mapping.
     270 * @param   cSegments   The number of segments in the array pointed to by paSegments.
     271 * @param   paSegments  The segments thats going to be mapped.
     272 * @param   fUnprotectOrProtect     When set the all mapped segments are made writable.
     273 *                                  When clean the segment protection is restored.
     274 */
     275int kLdrRdrProtect(PKLDRRDR pRdr, void *pvBase, uint32_t cSegments, PCKLDRSEG paSegments, unsigned fUnprotectOrProtect)
     276{
     277    KLDRRDR_VALIDATE(pRdr);
     278    return pRdr->pOps->pfnProtect(pRdr, pvBase, cSegments, paSegments, fUnprotectOrProtect);
     279}
     280
     281
     282/**
     283 * Unmaps a image mapping.
     284 *
     285 * @returns 0 on success, OS specific error code on failure.
     286 * @param   pRdr        The file provider instance.
     287 * @param   pvBase      The base address of the image mapping.
     288 * @param   cSegments   The number of segments in the array pointed to by paSegments.
     289 * @param   paSegments  The segments thats going to be mapped.
     290 */
     291int kLdrRdrUnmap(PKLDRRDR pRdr, void *pvBase, uint32_t cSegments, PCKLDRSEG paSegments)
     292{
     293    KLDRRDR_VALIDATE(pRdr);
     294    return pRdr->pOps->pfnUnmap(pRdr, pvBase, cSegments, paSegments);
    328295}
    329296
  • trunk/kLdr/kLdrRdrFile.c

    r2860 r2861  
    3535
    3636#elif defined(__WIN32__) || defined(__WIN64__) || defined(__WIN__)
     37# define WIN32_NO_STATUS
    3738# include <Windows.h>
    3839# ifndef __WIN__
    3940#  define __WIN__
    4041# endif
     42# include <ntsecapi.h>
     43# include <ntstatus.h>
     44
     45  /// @todo find a non-conflicting header with NTSTATUS, NTAPI, ++
     46  typedef LONG NTSTATUS;
     47  #define NT_SUCCESS(x) ((x)>=0)
     48
     49  typedef struct _OBJECT_ATTRIBUTES
     50  {
     51      ULONG   Length;
     52      HANDLE  RootDirectory;
     53      PUNICODE_STRING ObjectName;
     54      ULONG   Attributes;
     55      PVOID   SecurityDescriptor;
     56      PVOID   SecurityQualityOfService;
     57  } OBJECT_ATTRIBUTES, *POBJECT_ATTRIBUTES;
     58
     59  typedef enum _SECTION_INHERIT
     60  {
     61      ViewShare = 1,
     62      ViewUnmap = 2
     63  } SECTION_INHERIT;
     64
     65# define NTOSAPI __declspec(dllimport)
     66# define NtCurrentProcess() GetCurrentProcess()
     67
     68# ifndef MEM_DOS_LIM
     69#  define MEM_DOS_LIM 0x40000000UL
     70# endif
     71
     72  NTOSAPI
     73  NTSTATUS
     74  NTAPI
     75  NtCreateSection(
     76      OUT PHANDLE SectionHandle,
     77      IN ACCESS_MASK DesiredAccess,
     78      IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
     79      IN PLARGE_INTEGER SectionSize OPTIONAL,
     80      IN ULONG Protect,
     81      IN ULONG Attributes,
     82      IN HANDLE FileHandle OPTIONAL
     83  );
     84
     85  NTOSAPI
     86  NTSTATUS
     87  NTAPI
     88  NtMapViewOfSection(
     89      IN HANDLE SectionHandle,
     90      IN HANDLE ProcessHandle,
     91      IN OUT PVOID *BaseAddress,
     92      IN ULONG ZeroBits,
     93      IN ULONG CommitSize,
     94      IN OUT PLARGE_INTEGER SectionOffset OPTIONAL,
     95      IN OUT PSIZE_T ViewSize,
     96      IN SECTION_INHERIT InheritDisposition,
     97      IN ULONG AllocationType,
     98      IN ULONG Protect
     99  );
     100
     101  NTOSAPI
     102  NTSTATUS
     103  NTAPI
     104  NtUnmapViewOfSection(
     105      IN HANDLE ProcessHandle,
     106      IN PVOID BaseAddress
     107  );
     108
     109  NTOSAPI
     110  NTSTATUS
     111  NTAPI
     112  NtClose(
     113      IN HANDLE Handle
     114  );
     115
     116  NTOSAPI
     117  NTSTATUS
     118  NTAPI
     119  ZwProtectVirtualMemory(
     120      IN HANDLE ProcessHandle,
     121      IN OUT PVOID *BaseAddress,
     122      IN OUT PULONG ProtectSize,
     123      IN ULONG NewProtect,
     124      OUT PULONG OldProtect
     125  );
     126# define NtProtectVirtualMemory ZwProtectVirtualMemory
     127
     128  NTOSAPI
     129  NTSTATUS
     130  NTAPI
     131  NtAllocateVirtualMemory(
     132      IN HANDLE ProcessHandle,
     133      IN OUT PVOID *BaseAddress,
     134      IN ULONG ZeroBits,
     135      IN OUT PULONG AllocationSize,
     136      IN ULONG AllocationType,
     137      IN ULONG Protect
     138  );
     139
     140  NTOSAPI
     141  NTSTATUS
     142  NTAPI
     143  NtFreeVirtualMemory(
     144      IN HANDLE ProcessHandle,
     145      IN OUT PVOID *BaseAddress,
     146      IN OUT PULONG FreeSize,
     147      IN ULONG FreeType
     148  );
    41149
    42150#else
     
    46154#include <kLdr.h>
    47155#include "kLdrHlp.h"
     156
     157
     158/*******************************************************************************
     159*   Defined Constants And Macros                                               *
     160*******************************************************************************/
     161/** @def KLDRRDRFILE_STRICT
     162 * Define KLDRRDRFILE_STRICT to enabled strict checks in KLDRRDRFILE. */
     163#define KLDRRDRFILE_STRICT 1
     164
     165/** @def KLDRRDRFILE_ASSERT
     166 * Assert that an expression is true when KLDRRDRFILE_STRICT is defined.
     167 */
     168#ifdef KLDRRDRFILE_STRICT
     169# define KLDRRDRFILE_ASSERT(expr)  kldrHlpAssert(expr)
     170#else
     171# define KLDRRDRFILE_ASSERT(expr)  do {} while (0)
     172#endif
    48173
    49174
     
    102227*******************************************************************************/
    103228static void     kldrRdrFileDone(PKLDRRDR pRdr);
    104 static int      kldrRdrFileUnprepare(PKLDRRDR pRdr, void *pv, size_t cb);
    105 static int      kldrRdrFileUnmap(PKLDRRDR pRdr, void *pv, size_t cb);
    106 static int      kldrRdrFileProtect(PKLDRRDR pRdr, void *pv, size_t cb, KLDRPROT enmProt);
    107 static int      kldrRdrFileRefreshMap(PKLDRRDR pRdr, void *pv, size_t cb, KLDRPROT enmProt, off_t offFile, size_t cbFile);
    108 static int      kldrRdrFileMap(PKLDRRDR pRdr, void *pv, size_t cb, KLDRPROT enmProt, off_t offFile, size_t cbFile);
    109 static int      kldrRdrFilePrepare(PKLDRRDR pRdr, void **ppv, size_t cb, unsigned fFixed);
     229static int      kldrRdrFileUnmap(PKLDRRDR pRdr, void *pvBase, uint32_t cSegments, PCKLDRSEG paSegments);
     230static int      kldrRdrFileGenericUnmap(PKLDRRDR pRdr, PKLDRRDRFILEPREP pPrep, uint32_t cSegments, PCKLDRSEG paSegments);
     231static int      kldrRdrFileProtect(PKLDRRDR pRdr, void *pvBase, uint32_t cSegments, PCKLDRSEG paSegments, unsigned fUnprotectOrProtect);
     232static int      kldrRdrFileGenericProtect(PKLDRRDR pRdr, PKLDRRDRFILEPREP pPrep, uint32_t cSegments, PCKLDRSEG paSegments, unsigned fUnprotectOrProtect);
     233static int      kldrRdrFileRefresh(PKLDRRDR pRdr, void *pvBase, uint32_t cSegments, PCKLDRSEG paSegments);
     234static int      kldrRdrFileGenericRefresh(PKLDRRDR pRdr, PKLDRRDRFILEPREP pPrep, uint32_t cSegments, PCKLDRSEG paSegments);
     235static int      kldrRdrFileMap(PKLDRRDR pRdr, void *ppvBase, uint32_t cSegments, PCKLDRSEG paSegments, unsigned fFixed);
     236static int      kldrRdrFileGenericMap(PKLDRRDR pRdr, PKLDRRDRFILEPREP pPrep, uint32_t cSegments, PCKLDRSEG paSegments, unsigned fFixed);
    110237static size_t   kldrRdrFilePageSize(PKLDRRDR pRdr);
    111238static const char *kldrRdrFileName(PKLDRRDR pRdr);
     
    136263    kldrRdrFileName,
    137264    kldrRdrFilePageSize,
    138     kldrRdrFilePrepare,
    139265    kldrRdrFileMap,
    140     kldrRdrFileRefreshMap,
     266    kldrRdrFileRefresh,
    141267    kldrRdrFileProtect,
    142268    kldrRdrFileUnmap,
    143     kldrRdrFileUnprepare,
    144269    kldrRdrFileDone,
    145270    42
    146271};
     272
     273
     274#if defined(__WIN__) || defined(__NT__)
     275/**
     276 * Converts a kLdr segment protection to NT protection for a mapping.
     277 *
     278 * @returns Nt page protection.
     279 * @param   enmProt     kLdr protection.
     280 */
     281static ULONG kldrRdrFileGetNtMapProt(KLDRPROT enmProt)
     282{
     283    switch (enmProt)
     284    {
     285        case KLDRPROT_NOACCESS:             return PAGE_NOACCESS;
     286        case KLDRPROT_READONLY:             return PAGE_READONLY;
     287        case KLDRPROT_READWRITE:            return PAGE_READWRITE;
     288        case KLDRPROT_WRITECOPY:            return PAGE_WRITECOPY;
     289        case KLDRPROT_EXECUTE:              return PAGE_EXECUTE;
     290        case KLDRPROT_EXECUTE_READ:         return PAGE_EXECUTE_READ;
     291        case KLDRPROT_EXECUTE_READWRITE:    return PAGE_EXECUTE_READWRITE;
     292        case KLDRPROT_EXECUTE_WRITECOPY:    return PAGE_EXECUTE_WRITECOPY;
     293        default:                            return ~(ULONG)0;
     294    }
     295}
     296
     297
     298/**
     299 * Converts a kLdr segment protection to NT protection for a allocation.
     300 *
     301 * @returns Nt page protection.
     302 * @param   enmProt     kLdr protection.
     303 */
     304static ULONG kldrRdrFileGetNtAllocProt(KLDRPROT enmProt)
     305{
     306    switch (enmProt)
     307    {
     308        case KLDRPROT_NOACCESS:             return PAGE_NOACCESS;
     309        case KLDRPROT_READONLY:             return PAGE_READONLY;
     310        case KLDRPROT_WRITECOPY:
     311        case KLDRPROT_READWRITE:            return PAGE_READWRITE;
     312        case KLDRPROT_EXECUTE:              return PAGE_EXECUTE;
     313        case KLDRPROT_EXECUTE_READ:         return PAGE_EXECUTE_READ;
     314        case KLDRPROT_EXECUTE_WRITECOPY:
     315        case KLDRPROT_EXECUTE_READWRITE:    return PAGE_EXECUTE_READWRITE;
     316        default:                            return ~(ULONG)0;
     317    }
     318}
     319#endif
    147320
    148321
     
    159332 * @param   pFile   The instance data.
    160333 * @param   pv      The base of the region.
    161  * @param   cb      The size of the region.
    162334 */
    163 static PKLDRRDRFILEPREP kldrRdrFileFindPrepExact(PKLDRRDRFILE pFile, void *pv, size_t cb)
     335static PKLDRRDRFILEPREP kldrRdrFileFindPrepExact(PKLDRRDRFILE pFile, void *pv)
    164336{
    165337    int32_t i = pFile->cPreps;
    166338    while (i-- > 0)
    167         if (    pFile->aPreps[i].pv == pv
    168             ||  pFile->aPreps[i].cb == cb)
     339        if (pFile->aPreps[i].pv == pv)
    169340            return &pFile->aPreps[i];
    170341    return NULL;
     
    172343
    173344
    174 /**
    175  * Finds a prepared mapping region containing the specified region.
    176  *
    177  * @returns Pointer to the aPrep entry.
    178  * @param   pFile   The instance data.
    179  * @param   pv      The base of the sub region.
    180  * @param   cb      The size of the sub region.
    181  */
    182 static PKLDRRDRFILEPREP kldrRdrFileFindPrepWithin(PKLDRRDRFILE pFile, void *pv, size_t cb)
    183 {
    184     int32_t i = pFile->cPreps;
    185     while (i-- > 0)
    186         if ((uintptr_t)pv - (uintptr_t)pFile->aPreps[i].pv < pFile->aPreps[i].cb)
    187         {
    188             if ((uintptr_t)pv - (uintptr_t)pFile->aPreps[i].pv + cb <= pFile->aPreps[i].cb)
    189                 return &pFile->aPreps[i];
    190             return NULL;
    191         }
    192     return NULL;
    193 }
    194 
    195 
    196 /** @copydoc KLDRRDR::pfnUnprepare */
    197 static int      kldrRdrFileUnprepare(PKLDRRDR pRdr, void *pv, size_t cb)
     345/** @copydoc KLDRRDR::pfnUnmap */
     346static int      kldrRdrFileUnmap(PKLDRRDR pRdr, void *pvBase, uint32_t cSegments, PCKLDRSEG paSegments)
    198347{
    199348    PKLDRRDRFILE        pRdrFile = (PKLDRRDRFILE)pRdr;
    200     PKLDRRDRFILEPREP    pPrep = kldrRdrFileFindPrepExact(pRdrFile, pv, cb);
     349    PKLDRRDRFILEPREP    pPrep = kldrRdrFileFindPrepExact(pRdrFile, pvBase);
     350    int                 rc;
    201351    if (!pPrep)
    202352        return KLDR_ERR_INVALID_PARAMETER;
    203353
    204     return -1;
    205 }
    206 
    207 
    208 /** @copydoc KLDRRDR::pfnUnmap */
    209 static int      kldrRdrFileUnmap(PKLDRRDR pRdr, void *pv, size_t cb)
     354#if defined(__WIN__) || defined(__NT__)
     355    if (pPrep->hSection != NULL)
     356    {
     357        /** @todo implement me. */
     358        return -1;
     359    }
     360#endif
     361
     362    rc = kldrRdrFileGenericUnmap(pRdr, pPrep, cSegments, paSegments);
     363
     364    /* remove the mapping data on success. */
     365    if (!rc)
     366    {
     367        pRdrFile->cPreps--;
     368        if (pPrep != &pRdrFile->aPreps[pRdrFile->cPreps])
     369            *pPrep = pRdrFile->aPreps[pRdrFile->cPreps];
     370    }
     371    return rc;
     372}
     373
     374
     375/** Generic implementation of kldrRdrFileUnmap. */
     376static int kldrRdrFileGenericUnmap(PKLDRRDR pRdr, PKLDRRDRFILEPREP pPrep, uint32_t cSegments, PCKLDRSEG paSegments)
     377{
     378    kldrRdrFileGenericProtect(pRdr, pPrep, cSegments, paSegments, 1 /* unprotect */);
     379    return kldrHlpPageFree(pPrep->pv, pPrep->cb);
     380}
     381
     382
     383/** @copydoc KLDRRDR::pfnProtect */
     384static int      kldrRdrFileProtect(PKLDRRDR pRdr, void *pvBase, uint32_t cSegments, PCKLDRSEG paSegments, unsigned fUnprotectOrProtect)
    210385{
    211386    PKLDRRDRFILE        pRdrFile = (PKLDRRDRFILE)pRdr;
    212     PKLDRRDRFILEPREP    pPrep = kldrRdrFileFindPrepExact(pRdrFile, pv, cb);
     387    PKLDRRDRFILEPREP    pPrep = kldrRdrFileFindPrepExact(pRdrFile, pvBase);
    213388    if (!pPrep)
    214389        return KLDR_ERR_INVALID_PARAMETER;
    215390
    216     return -1;
    217 }
    218 
    219 
    220 /** @copydoc KLDRRDR::pfnProtect */
    221 static int      kldrRdrFileProtect(PKLDRRDR pRdr, void *pv, size_t cb, KLDRPROT enmProt)
     391#if defined(__WIN__) || defined(__NT__)
     392    if (pPrep->hSection != NULL)
     393    {
     394        /** @todo implement me. */
     395        return -1;
     396    }
     397#endif
     398
     399    return kldrRdrFileGenericProtect(pRdr, pPrep, cSegments, paSegments, fUnprotectOrProtect);
     400}
     401
     402
     403/** Generic implementation of kldrRdrFileProtect. */
     404static int kldrRdrFileGenericProtect(PKLDRRDR pRdr, PKLDRRDRFILEPREP pPrep, uint32_t cSegments, PCKLDRSEG paSegments, unsigned fUnprotectOrProtect)
     405{
     406    uint32_t i;
     407
     408    /*
     409     * Iterate the segments and apply memory protection changes.
     410     */
     411    for (i = 0; i < cSegments; i++)
     412    {
     413        int rc;
     414        void *pv;
     415        KLDRPROT enmProt;
     416
     417        if (paSegments[i].RVA == NIL_KLDRADDR)
     418            continue;
     419
     420        /* calc new protection. */
     421        enmProt = paSegments[i].enmProt;
     422        if (fUnprotectOrProtect)
     423        {
     424            switch (enmProt)
     425            {
     426                case KLDRPROT_NOACCESS:
     427                case KLDRPROT_READONLY:
     428                case KLDRPROT_READWRITE:
     429                case KLDRPROT_WRITECOPY:
     430                    enmProt = KLDRPROT_READWRITE;
     431                    break;
     432                case KLDRPROT_EXECUTE:
     433                case KLDRPROT_EXECUTE_READ:
     434                case KLDRPROT_EXECUTE_READWRITE:
     435                case KLDRPROT_EXECUTE_WRITECOPY:
     436                    enmProt = KLDRPROT_EXECUTE_READWRITE;
     437                    break;
     438                default:
     439                    KLDRRDRFILE_ASSERT(!"bad enmProt");
     440                    return -1;
     441            }
     442        }
     443        else
     444        {
     445            /* copy on write -> normal write. */
     446            if (enmProt == KLDRPROT_EXECUTE_WRITECOPY)
     447                enmProt = KLDRPROT_EXECUTE_READWRITE;
     448            else if (enmProt == KLDRPROT_WRITECOPY)
     449                enmProt = KLDRPROT_READWRITE;
     450        }
     451
     452        pv = (uint8_t *)pPrep->pv + paSegments[i].RVA;
     453
     454        rc = kldrHlpPageProtect(pv, paSegments[i].cbMapped, enmProt);
     455        if (rc)
     456            break;
     457    }
     458
     459    return 0;
     460}
     461
     462
     463/** @copydoc KLDRRDR::pfnRefresh */
     464static int      kldrRdrFileRefresh(PKLDRRDR pRdr, void *pvBase, uint32_t cSegments, PCKLDRSEG paSegments)
    222465{
    223466    PKLDRRDRFILE        pRdrFile = (PKLDRRDRFILE)pRdr;
    224     PKLDRRDRFILEPREP    pPrep = kldrRdrFileFindPrepExact(pRdrFile, pv, cb);
     467    PKLDRRDRFILEPREP    pPrep = kldrRdrFileFindPrepExact(pRdrFile, pvBase);
    225468    if (!pPrep)
    226469        return KLDR_ERR_INVALID_PARAMETER;
    227470
    228     return -1;
    229 }
    230 
    231 
    232 /** @copydoc KLDRRDR::pfnRefreshMap */
    233 static int      kldrRdrFileRefreshMap(PKLDRRDR pRdr, void *pv, size_t cb, KLDRPROT enmProt, off_t offFile, size_t cbFile)
     471#if defined(__WIN__) || defined(__NT__)
     472    if (pPrep->hSection != NULL)
     473    {
     474        /** @todo implement me. */
     475        return -1;
     476    }
     477#endif
     478
     479    return kldrRdrFileGenericRefresh(pRdr, pPrep, cSegments, paSegments);
     480}
     481
     482
     483/** Generic implementation of kldrRdrFileRefresh. */
     484static int      kldrRdrFileGenericRefresh(PKLDRRDR pRdr, PKLDRRDRFILEPREP pPrep, uint32_t cSegments, PCKLDRSEG paSegments)
     485{
     486    int rc;
     487    int rc2;
     488    uint32_t i;
     489
     490    /*
     491     * Make everything writable again.
     492     */
     493    rc = kldrRdrFileGenericProtect(pRdr, pPrep, cSegments, paSegments, 1 /* unprotect */);
     494    if (rc)
     495    {
     496        kldrRdrFileGenericProtect(pRdr, pPrep, cSegments, paSegments, 0 /* protect */);
     497        return rc;
     498    }
     499
     500    /*
     501     * Clear everything.
     502     */
     503    /** @todo only zero the areas not covered by raw file bits. */
     504    kLdrHlpMemSet(pPrep->pv, 0, pPrep->cb);
     505
     506    /*
     507     * Reload all the segments.
     508     * We could possibly skip some segments, but we currently have
     509     * no generic way of figuring out which at the moment.
     510     */
     511    for (i = 0; i < cSegments; i++)
     512    {
     513        void *pv;
     514
     515        if (    paSegments[i].RVA == NIL_KLDRADDR
     516            ||  !paSegments[i].cbFile)
     517            continue;
     518
     519        pv = (uint8_t *)pPrep->pv + paSegments[i].RVA;
     520        rc = pRdr->pOps->pfnRead(pRdr, pv, paSegments[i].cbFile, paSegments[i].offFile);
     521        if (rc)
     522            break;
     523    }
     524
     525    /*
     526     * Protect the bits again.
     527     */
     528    rc2 = kldrRdrFileGenericProtect(pRdr, pPrep, cSegments, paSegments, 0 /* protect */);
     529    if (rc2 && rc)
     530        rc = rc2;
     531
     532    return rc;
     533}
     534
     535
     536/** @copydoc KLDRRDR::pfnMap */
     537static int      kldrRdrFileMap(PKLDRRDR pRdr, void **ppvBase, uint32_t cSegments, PCKLDRSEG paSegments, unsigned fFixed)
    234538{
    235539    PKLDRRDRFILE        pRdrFile = (PKLDRRDRFILE)pRdr;
    236     PKLDRRDRFILEPREP    pPrep = kldrRdrFileFindPrepExact(pRdrFile, pv, cb);
    237     if (!pPrep)
    238         return KLDR_ERR_INVALID_PARAMETER;
    239 
    240     return -1;
    241 }
    242 
    243 
    244 /** @copydoc KLDRRDR::pfnMap */
    245 static int      kldrRdrFileMap(PKLDRRDR pRdr, void *pv, size_t cb, KLDRPROT enmProt, off_t offFile, size_t cbFile)
    246 {
    247     PKLDRRDRFILE        pRdrFile = (PKLDRRDRFILE)pRdr;
    248     PKLDRRDRFILEPREP    pPrep = kldrRdrFileFindPrepExact(pRdrFile, pv, cb);
    249     if (!pPrep)
    250         return KLDR_ERR_INVALID_PARAMETER;
    251 
    252     return -1;
    253 }
    254 
    255 
    256 /** @copydoc KLDRRDR:pfnPrepare */
    257 static int      kldrRdrFilePrepare(PKLDRRDR pRdr, void **ppv, size_t cb, unsigned fFixed)
    258 {
    259 #ifdef __OS2__
    260 
    261 
    262 #elif defined(__WIN__)
    263 
    264 #else
    265 # error "port me."
    266 #endif
    267     return -1;
     540    PKLDRRDRFILEPREP    pPrep = &pRdrFile->aPreps[pRdrFile->cPreps];
     541    KLDRSIZE            cbTotal;
     542    const size_t        cbPage = pRdr->pOps->pfnPageSize(pRdr);
     543    int                 rc;
     544    uint32_t            i;
     545
     546    if (pRdrFile->cPreps >= KLDR_ELEMENTS(pRdrFile->aPreps))
     547        return KLDR_ERR_TOO_MANY_MAPPINGS;
     548
     549    /*
     550     * Calc the total mapping space needed.
     551     */
     552    cbTotal = 0;
     553    for (i = 0; i < cSegments; i++)
     554    {
     555        KLDRSIZE uRVASegmentEnd;
     556        if (paSegments[i].RVA == NIL_KLDRADDR)
     557            continue;
     558        uRVASegmentEnd = paSegments[i].RVA + paSegments[i].cbMapped;
     559        if (cbTotal < uRVASegmentEnd)
     560            cbTotal = uRVASegmentEnd;
     561    }
     562    pPrep->cb = (size_t)cbTotal;
     563    if (pPrep->cb != cbTotal)
     564        return KLDR_ERR_ADDRESS_OVERFLOW;
     565    pPrep->cb = (pPrep->cb + (cbPage - 1)) & ~(cbPage- 1);
     566
     567#if defined(__WIN__) || defined(__NT__)
     568    /*
     569     * The NT memory mapped file API sucks in a lot of ways. Unless you're actually
     570     * trying to map a PE image and the kernel can parse the file for it self, the
     571     * API just isn't up to scratch.
     572     *
     573     * Problems:
     574     *      1. Reserving memory for the views is risky because you can't reserve and
     575     *         map into the reserved space. So, other threads might grab the memory
     576     *         before we get to it.
     577     *      2. The page aligning of file offsets makes it impossible to map most
     578     *         executable images since these are commonly sector aligned.
     579     *      3. When mapping a read+execute file, its not possible to create section
     580     *         larger than the file since the section size is bound to the data file
     581     *         size. This wouldn't have been such a problem if it was possible to
     582     *         map views beyond the section restriction, i.e. have a file size and
     583     *         view size.
     584     *      4. Only x86 can map views at page granularity it seems, and that only
     585     *         using an undocument flag. The default granularity is 64KB.
     586     *      5. There is more crappyness here...
     587     *
     588     * So, first we'll have to check if we can the file using the crappy NT APIs.
     589     * Chances are we can't.
     590     */
     591    for (i = 0; i < cSegments; i++)
     592    {
     593        if (paSegments[i].RVA == NIL_KLDRADDR)
     594            continue;
     595
     596        /* The file backing of the segments must be page aligned. */
     597        if (    paSegments[i].cbFile
     598            &&  paSegments[i].offFile & (cbPage - 1))
     599            break;
     600
     601        /* Only page alignment gaps between the file size and the mapping size. */
     602        if (    paSegments[i].cbFile
     603            &&  (paSegments[i].cbFile & ~(cbPage - 1)) != (paSegments[i].cbMapped & ~(cbPage - 1)) )
     604            break;
     605
     606        /* The mapping addresses of the segments must be page aligned.
     607         * Non-x86 will probably require 64KB alignment here. */
     608        if (paSegments[i].RVA & (cbPage - 1))
     609            break;
     610
     611        /* If we do have to allocate the segment it's RVA must be 64KB aligned. */
     612        if (    !paSegments[i].cbFile
     613            &&  (paSegments[i].RVA & 0xffff))
     614            break;
     615    }
     616    /** @todo if this is a PE image, we might just try a SEC_IMAGE mapping. It'll work if the host and image machines matches. */
     617    if (i == cSegments)
     618    {
     619        /* WOW! it may work out! Incredible! */
     620        SIZE_T          ViewSize;
     621        LARGE_INTEGER   SectionOffset;
     622        LARGE_INTEGER   MaxiumSize;
     623        NTSTATUS        Status;
     624        PVOID           pv;
     625
     626        MaxiumSize.QuadPart = pRdr->pOps->pfnSize(pRdr);
     627        if (MaxiumSize.QuadPart > (LONGLONG)cbTotal)
     628            MaxiumSize.QuadPart = cbTotal;
     629
     630        Status = NtCreateSection(&pPrep->hSection,
     631                                 SECTION_MAP_EXECUTE | SECTION_MAP_READ,    /* desired access */
     632                                 NULL,                                      /* object attributes */
     633                                 &MaxiumSize,
     634                                 PAGE_EXECUTE_WRITECOPY,                    /* page attributes */
     635                                 SEC_COMMIT,                                /* section attributes */
     636                                 pRdrFile->File);
     637        if (!NT_SUCCESS(Status))
     638            return (int)Status;
     639
     640        /*
     641         * Determin the base address.
     642         */
     643        if (fFixed)
     644            pPrep->pv = *ppvBase;
     645        else
     646        {
     647            pv = NULL;
     648            ViewSize = (size_t)cbTotal;
     649
     650            Status = NtAllocateVirtualMemory(NtCurrentProcess(),
     651                                             &pv,
     652                                             0,                             /* ZeroBits */
     653                                             &ViewSize,
     654                                             MEM_RESERVE,
     655                                             PAGE_READONLY);
     656            if (NT_SUCCESS(Status))
     657            {
     658                pPrep->pv = *ppvBase = pv;
     659                ViewSize = 0;
     660                Status = NtFreeVirtualMemory(NtCurrentProcess(), &pv, &ViewSize, MEM_RELEASE);
     661            }
     662            if (!NT_SUCCESS(Status))
     663            {
     664                NtClose(pPrep->hSection);
     665                return Status;
     666            }
     667        }
     668
     669        /*
     670         * Map the segments.
     671         */
     672        for (i = 0; i < cSegments; i++)
     673        {
     674            ULONG fPageProt;
     675
     676            if (paSegments[i].RVA == NIL_KLDRADDR)
     677                continue;
     678
     679            pv = (uint8_t *)pPrep->pv + paSegments[i].RVA;
     680            if (paSegments[i].cbFile)
     681            {
     682                SectionOffset.QuadPart = paSegments[i].offFile;
     683                ViewSize = paSegments[i].cbFile;
     684                fPageProt = kldrRdrFileGetNtMapProt(paSegments[i].enmProt);
     685                // STATUS_MAPPED_ALIGNMENT
     686                // STATUS_CONFLICTING_ADDRESSES
     687                // STATUS_INVALID_VIEW_SIZE
     688                Status = NtMapViewOfSection(pPrep->hSection, NtCurrentProcess(),
     689                                            &pv,
     690                                            0,                                  /* ZeroBits */
     691                                            0,                                  /* CommitSize */
     692                                            &SectionOffset,                     /* SectionOffset */
     693                                            &ViewSize,
     694                                            ViewUnmap,
     695                                            MEM_DOS_LIM,                        /* AllocationType */
     696                                            fPageProt);
     697                /* do we have to zero anything? */
     698                if (    NT_SUCCESS(Status)
     699                    &&  0/*later*/)
     700                {
     701                    //ULONG OldPageProt = 0;
     702                    //NtProtectVirtualMemory(NtCurrentProcess(), &pv, &ViewSize, ,
     703                }
     704            }
     705            else
     706            {
     707                ViewSize = paSegments[i].cbMapped;
     708                fPageProt = kldrRdrFileGetNtAllocProt(paSegments[i].enmProt);
     709                Status = NtAllocateVirtualMemory(NtCurrentProcess(),
     710                                                 &pv,
     711                                                 0,                             /* ZeroBits */
     712                                                 &ViewSize,
     713                                                 MEM_COMMIT,
     714                                                 fPageProt);
     715            }
     716            if (!NT_SUCCESS(Status))
     717                break;
     718        }
     719
     720        /*
     721         * On success, commit the mapping and return.
     722         */
     723        if (NT_SUCCESS(Status))
     724        {
     725            pRdrFile->cPreps++;
     726            return 0;
     727        }
     728
     729        /* bail out and fall back on the generic code. */
     730        while (i-- > 0)
     731        {
     732            PVOID pv;
     733
     734            if (paSegments[i].RVA == NIL_KLDRADDR)
     735                continue;
     736
     737            pv = (uint8_t *)pPrep->pv + paSegments[i].RVA;
     738            if (paSegments[i].cbFile)
     739                NtUnmapViewOfSection(NtCurrentProcess(), pv);
     740            else
     741                NtFreeVirtualMemory(NtCurrentProcess(), &pv, NULL, MEM_RELEASE);
     742        }
     743        NtClose(pPrep->hSection);
     744    }
     745    /* else: fall back to the generic code */
     746    pPrep->hSection = NULL;
     747#endif
     748
     749    /*
     750     * Use the generic map emulation.
     751     */
     752    pPrep->pv = fFixed ? *ppvBase : NULL;
     753    rc = kldrRdrFileGenericMap(pRdr, pPrep, cSegments, paSegments, fFixed);
     754    if (!rc)
     755    {
     756        *ppvBase = pPrep->pv;
     757        pRdrFile->cPreps++;
     758    }
     759
     760    return rc;
     761}
     762
     763
     764/** Generic implementation of kldrRdrFileMap. */
     765static int  kldrRdrFileGenericMap(PKLDRRDR pRdr, PKLDRRDRFILEPREP pPrep, uint32_t cSegments, PCKLDRSEG paSegments, unsigned fFixed)
     766{
     767    int rc;
     768    uint32_t i;
     769
     770    /*
     771     * Generic mapping code using kldrHlpPageAlloc(), kldrHlpPageFree() and kldrHlpPageProtect().
     772     */
     773    rc = kldrHlpPageAlloc(&pPrep->pv, pPrep->cb, KLDRPROT_EXECUTE_READWRITE, fFixed);
     774    if (rc)
     775        return rc;
     776
     777    /*
     778     * Load the data.
     779     */
     780    for (i = 0; i < cSegments; i++)
     781    {
     782        void *pv;
     783
     784        if (    paSegments[i].RVA == NIL_KLDRADDR
     785            ||  !paSegments[i].cbFile)
     786            continue;
     787
     788        pv = (uint8_t *)pPrep->pv + paSegments[i].RVA;
     789        rc = pRdr->pOps->pfnRead(pRdr, pv, paSegments[i].cbFile, paSegments[i].offFile);
     790        if (rc)
     791            break;
     792    }
     793
     794    /*
     795     * Set segment protection.
     796     */
     797    if (!rc)
     798    {
     799        rc = kldrRdrFileGenericProtect(pRdr, pPrep, cSegments, paSegments, 0 /* protect */);
     800        if (!rc)
     801            return 0;
     802        kldrRdrFileGenericProtect(pRdr, pPrep, cSegments, paSegments, 1 /* unprotect */);
     803    }
     804
     805    /* bailout */
     806    kldrHlpPageFree(pPrep->pv, pPrep->cb);
     807    return rc;
    268808}
    269809
     
    5721112    SecAttr.lpSecurityDescriptor = NULL;
    5731113    SecAttr.nLength = 0;
    574     File = CreateFile(pszFilename, GENERIC_READ, FILE_SHARE_READ, &SecAttr, OPEN_ALWAYS, 0, NULL);
     1114    File = CreateFile(pszFilename, GENERIC_READ | GENERIC_EXECUTE, FILE_SHARE_READ, &SecAttr, OPEN_ALWAYS, 0, NULL);
    5751115    if (File == INVALID_HANDLE_VALUE)
    5761116        return GetLastError();
  • trunk/kLdr/tstkLdrMod.c

    r2860 r2861  
    4040*******************************************************************************/
    4141/** The default base address used in the tests. */
    42 #define MY_BASEADDRESS      0x4200000
     42#define MY_BASEADDRESS      0x2400000
    4343
    4444
     
    6969
    7070
     71/** Dummy import resolver callback. */
     72static int BasicTestsGetImport(PKLDRMOD pMod, uint32_t iImport, uint32_t iSymbol, const char *pszSymbol,
     73                               PKLDRADDR puValue, uint32_t *pfKind, void *pvUser)
     74{
     75    *puValue = 0xdeadface;
     76    *pfKind = KLDRSYMKIND_NO_BIT | KLDRSYMKIND_NO_TYPE;
     77    return 0;
     78}
     79
     80
     81
     82/**
     83 * Performs basic relocation tests.
     84 */
     85static int BasicTestsRelocate(PKLDRMOD pMod, void *pvBits, void *pvBits2)
     86{
     87    const size_t cbImage = (size_t)kLdrModSize(pMod);
     88    int rc;
     89
     90    printf("* Relocation test...\n");
     91
     92    /*
     93     * Get the same bits again to check that we get the same result.
     94     */
     95    memset(pvBits2, 0xfe, cbImage);
     96    rc = kLdrModGetBits(pMod, pvBits2, (uintptr_t)pvBits, BasicTestsGetImport, NULL);
     97    if (rc)
     98        return Failure("failed to get image bits, rc=%d (a)", rc);
     99    if (memcmp(pvBits2, pvBits, cbImage))
     100        return Failure("relocation test failed, mismatching bits (a)");
     101
     102    /*
     103     * Short relocation round trip.
     104     */
     105    rc = kLdrModRelocateBits(pMod, pvBits2, 0x1000, (uintptr_t)pvBits, BasicTestsGetImport, NULL);
     106    if (rc)
     107        return Failure("failed to relocate, rc=%d (b1)");
     108    rc = kLdrModRelocateBits(pMod, pvBits2, (uintptr_t)pvBits, 0x1000, BasicTestsGetImport, NULL);
     109    if (rc)
     110        return Failure("failed to relocate, rc=%d (b2)");
     111    if (memcmp(pvBits2, pvBits, cbImage))
     112        return Failure("relocation test failed, mismatching bits (b)");
     113
     114    /*
     115     * Longer trip where we also check the intermediate results.
     116     */
     117    /* stage one */
     118    rc = kLdrModRelocateBits(pMod, pvBits, 0x1000000, (uintptr_t)pvBits, BasicTestsGetImport, NULL);
     119    if (rc)
     120        return Failure("failed to relocate, rc=%d (c1)");
     121    memset(pvBits2, 0xfe, cbImage);
     122    rc = kLdrModGetBits(pMod, pvBits2, 0x1000000, BasicTestsGetImport, NULL);
     123    if (rc)
     124        return Failure("failed to get image bits, rc=%d (c1)", rc);
     125    if (memcmp(pvBits2, pvBits, cbImage))
     126        return Failure("relocation test failed, mismatching bits (c1)");
     127
     128    /* stage two */
     129    rc = kLdrModRelocateBits(pMod, pvBits, ~(uintptr_t)0x1010000, 0x1000000, BasicTestsGetImport, NULL);
     130    if (rc)
     131        return Failure("failed to relocate, rc=%d (c2)");
     132    memset(pvBits2, 0xef, cbImage);
     133    rc = kLdrModGetBits(pMod, pvBits2, ~(uintptr_t)0x1010000, BasicTestsGetImport, NULL);
     134    if (rc)
     135        return Failure("failed to get image bits, rc=%d (c2)", rc);
     136    if (memcmp(pvBits2, pvBits, cbImage))
     137        return Failure("relocation test failed, mismatching bits (c2)");
     138
     139    /* stage three */
     140    rc = kLdrModRelocateBits(pMod, pvBits, MY_BASEADDRESS, ~(uintptr_t)0x1010000, BasicTestsGetImport, NULL);
     141    if (rc)
     142        return Failure("failed to relocate, rc=%d (c3)");
     143    memset(pvBits2, 0xef, cbImage);
     144    rc = kLdrModGetBits(pMod, pvBits2, MY_BASEADDRESS, BasicTestsGetImport, NULL);
     145    if (rc)
     146        return Failure("failed to get image bits, rc=%d (c3)", rc);
     147    if (memcmp(pvBits2, pvBits, cbImage))
     148        return Failure("relocation test failed, mismatching bits (c3)");
     149
     150    /* stage four */
     151    rc = kLdrModRelocateBits(pMod, pvBits, ~(uintptr_t)0 / 2 - 0x10000, MY_BASEADDRESS, BasicTestsGetImport, NULL);
     152    if (rc)
     153        return Failure("failed to relocate, rc=%d (c4)");
     154    memset(pvBits2, 0xdc, cbImage);
     155    rc = kLdrModGetBits(pMod, pvBits2, ~(uintptr_t)0 / 2 - 0x10000, BasicTestsGetImport, NULL);
     156    if (rc)
     157        return Failure("failed to get image bits, rc=%d (c4)", rc);
     158    if (memcmp(pvBits2, pvBits, cbImage))
     159        return Failure("relocation test failed, mismatching bits (c4)");
     160
     161    /* return */
     162    rc = kLdrModRelocateBits(pMod, pvBits, (uintptr_t)pvBits, ~(uintptr_t)0 / 2 - 0x10000, BasicTestsGetImport, NULL);
     163    if (rc)
     164        return Failure("failed to relocate, rc=%d (c5)");
     165    memset(pvBits2, 0xcd, cbImage);
     166    rc = kLdrModGetBits(pMod, pvBits2, (uintptr_t)pvBits, BasicTestsGetImport, NULL);
     167    if (rc)
     168        return Failure("failed to get image bits, rc=%d (c5)", rc);
     169    if (memcmp(pvBits2, pvBits, cbImage))
     170        return Failure("relocation test failed, mismatching bits (c5)");
     171
     172    return 0;
     173}
     174
     175
    71176/**
    72177 * Dump symbols and check that we can query each of them recursivly.
     
    91196                                &uValue2, &fKind2);
    92197        if (rc)
    93             return Failure("Couldn't find symbol %#x (%s) by ordinal. rc=%d\n", iSymbol, pszSymbol, rc);
     198            return Failure("Couldn't find symbol %#x (%s) by ordinal. rc=%d", iSymbol, pszSymbol, rc);
    94199        if (uValue != uValue2)
    95             return Failure("Symbol %#x (%s): Value mismatch %016" PRI_KLDRADDR " != %016" PRI_KLDRADDR " (enum!=query/ord)  pvBits=%p\n",
     200            return Failure("Symbol %#x (%s): Value mismatch %016" PRI_KLDRADDR " != %016" PRI_KLDRADDR " (enum!=query/ord)  pvBits=%p",
    96201                           iSymbol, pszSymbol, uValue, uValue2, pvUser);
    97202        if (fKind != fKind2)
    98             return Failure("Symbol %#x (%s): Kind mismatch %#x != %#x (enum!=query/ord) pvBits=%p\n",
     203            return Failure("Symbol %#x (%s): Kind mismatch %#x != %#x (enum!=query/ord) pvBits=%p",
    99204                           iSymbol, pszSymbol, fKind, fKind2, pvUser);
    100205    }
     
    106211                                &uValue2, &fKind2);
    107212        if (rc)
    108             return Failure("Couldn't find symbol %#x (%s) by name. rc=%d\n", iSymbol, pszSymbol, rc);
     213            return Failure("Couldn't find symbol %#x (%s) by name. rc=%d", iSymbol, pszSymbol, rc);
    109214        if (uValue != uValue2)
    110             return Failure("Symbol %#x (%s): Value mismatch %016" PRI_KLDRADDR " != %016" PRI_KLDRADDR " (enum!=query/name) pvBits=%p\n",
     215            return Failure("Symbol %#x (%s): Value mismatch %016" PRI_KLDRADDR " != %016" PRI_KLDRADDR " (enum!=query/name) pvBits=%p",
    111216                           iSymbol, pszSymbol, uValue, uValue2, pvUser);
    112217        if (fKind != fKind2)
    113             return Failure("Symbol %#x (%s): Kind mismatch %#x != %#x (enum!=query/name) pvBits=%p\n",
     218            return Failure("Symbol %#x (%s): Kind mismatch %#x != %#x (enum!=query/name) pvBits=%p",
    114219                           iSymbol, pszSymbol, fKind, fKind2, pvUser);
    115220    }
     
    153258    KLDRSTACKINFO StackInfo;
    154259
     260    printf("* Testing queries with pvBits=%p...\n", pvBits);
     261
    155262    /*
    156263     * Get the import modules.
     
    159266    printf("cImports=%d\n", cImports);
    160267    if (cImports < 0)
    161         return Failure("failed to allocate %d bytes for the image", cImports);
     268        return Failure("failed to query the number of import, cImports=%d", cImports);
    162269    for (i = 0; i < cImports; i++)
    163270    {
     
    201308    if (MainEPAddress == ~(KLDRADDR)42)
    202309        return Failure("MainEPAddress wasn't set.");
     310    if (MainEPAddress != NIL_KLDRADDR && MainEPAddress < MY_BASEADDRESS)
     311        return Failure("Bad MainEPAddress (a).");
     312    if (MainEPAddress != NIL_KLDRADDR && MainEPAddress >= MY_BASEADDRESS + kLdrModSize(pMod))
     313        return Failure("Bad MainEPAddress (b).");
    203314
    204315    /*
     
    256367*/
    257368
    258     return 0;
    259 }
    260 
    261 
    262 /** Dummy import resolver callback. */
    263 static int BasicTestsGetImport(PKLDRMOD pMod, uint32_t iImport, uint32_t iSymbol, const char *pszSymbol,
    264                                PKLDRADDR puValue, uint32_t *pfKind, void *pvUser)
    265 {
    266     *puValue = 0xdeadface;
    267     *pfKind = KLDRSYMKIND_NO_BIT | KLDRSYMKIND_NO_TYPE;
    268369    return 0;
    269370}
     
    354455    }
    355456
     457
    356458    /*
    357459     * Get image the size and query the image bits.
    358460     */
     461    printf("* Testing user mapping...\n");
     462
    359463    cbImage = (size_t)kLdrModSize(pMod);
    360464    if (cbImage != kLdrModSize(pMod))
    361         return Failure("aborting test because the image is too huge!\n");
     465        return Failure("aborting test because the image is too huge!");
    362466    pvBits = malloc((size_t)cbImage);
    363467    if (!pvBits)
    364         return Failure("failed to allocate %d bytes for the image\n", cbImage);
     468        return Failure("failed to allocate %d bytes for the image", cbImage);
    365469
    366470    rc = kLdrModGetBits(pMod, pvBits, (uintptr_t)pvBits, BasicTestsGetImport, NULL);
    367471    if (rc)
    368         return Failure("failed to allocate %d bytes for the image\n", cbImage);
     472        return Failure("failed to get image bits, rc=%d", rc);
    369473
    370474    /*
     
    372476     */
    373477    rc = BasicTestsSub2(pMod, pvBits);
     478    if (!rc)
     479    {
     480        /*
     481         * Test relocating the bits in a few different ways before we're done with them.
     482         */
     483        void *pvBits2 = malloc((size_t)cbImage);
     484        if (pvBits2)
     485        {
     486            rc = BasicTestsRelocate(pMod, pvBits, pvBits2);
     487            free(pvBits2);
     488        }
     489        else
     490            rc = Failure("failed to allocate %d bytes for the 2nd image", cbImage);
     491    }
     492
    374493    free(pvBits);
    375494    return rc;
     
    378497
    379498/**
     499 * Tests the mapping related api, after mapping.
     500 */
     501static int BasicTestsSubMap2(PKLDRMOD pMod)
     502{
     503    int rc;
     504
     505    rc = kLdrModFixupMapping(pMod, BasicTestsGetImport, NULL);
     506    if (rc)
     507        return Failure("kLdrModFixupMapping (a) failed, rc=%d", rc);
     508
     509    rc = kLdrModReload(pMod);
     510    if (rc)
     511        return Failure("kLdrModReload (a) failed, rc=%d", rc);
     512
     513    rc = kLdrModReload(pMod);
     514    if (rc)
     515        return Failure("kLdrModReload (b) failed, rc=%d", rc);
     516
     517    rc = kLdrModFixupMapping(pMod, BasicTestsGetImport, NULL);
     518    if (rc)
     519        return Failure("kLdrModFixupMapping (b) failed, rc=%d", rc);
     520
     521    rc = kLdrModAllocTLS(pMod);
     522    if (rc)
     523        return Failure("kLdrModAllocTLS (a) failed, rc=%d", rc);
     524    kLdrModFreeTLS(pMod);
     525
     526    rc = kLdrModAllocTLS(pMod);
     527    if (rc)
     528        return Failure("kLdrModAllocTLS (b) failed, rc=%d", rc);
     529    kLdrModFreeTLS(pMod);
     530
     531    /*
     532     * Repeat the BasicTestsSub2 with pvBits as NULL to test module
     533     * interpreters that can utilize the mapping.
     534     */
     535    rc = BasicTestsSub2(pMod, NULL);
     536    if (rc)
     537        return Failure("BasicTestsSub2 in Map2 failed, rc=%d", rc);
     538    return 0;
     539}
     540
     541
     542/**
    380543 * Tests the mapping related api.
    381544 */
    382545static int BasicTestsSubMap(PKLDRMOD pMod)
    383546{
    384     int rc;
     547    int rc, rc2;
     548    printf("* Mapping tests...\n");
    385549
    386550    rc = kLdrModMap(pMod);
    387551    if (rc)
    388         return Failure("kLdrModMap failed, rc=%d\n", rc);
    389 
    390     return 0;
     552        return Failure("kLdrModMap failed, rc=%d", rc);
     553    rc = BasicTestsSubMap2(pMod);
     554    rc2 = kLdrModUnmap(pMod);
     555    if (rc2)
     556    {
     557        Failure("kLdrModUnmap failed, rc=%d", rc2);
     558        rc = rc ? rc : rc2;
     559    }
     560
     561    printf("* Mapping tests done.\n");
     562    return rc;
    391563}
    392564
     
    400572    int rc, rc2;
    401573
    402     printf("tstLdrMod: Testing '%s'\n", pszFilename);
     574    printf("tstLdrMod: Testing '%s'", pszFilename);
    403575    rc = kLdrModOpen(pszFilename, &pMod);
    404576    if (!rc)
     
    407579        if (!rc)
    408580            rc = BasicTestsSubMap(pMod);
     581        if (!rc)
     582            rc = BasicTestsSub2(pMod, NULL);
    409583        rc2 = kLdrModClose(pMod);
    410584        if (rc2)
    411             Failure("failed to close '%s', rc=%d\n", pszFilename, rc);
     585            Failure("failed to close '%s', rc=%d", pszFilename, rc);
    412586        if (rc2 && !rc)
    413587            rc = rc2;
    414588    }
    415589    else
    416         Failure("Failed to open '%s', rc=%d\n", pszFilename, rc);
     590        Failure("Failed to open '%s', rc=%d", pszFilename, rc);
    417591    return rc ? 1 : 0;
    418592}
Note: See TracChangeset for help on using the changeset viewer.