Changeset 2861
- Timestamp:
- Nov 10, 2006, 4:04:42 AM (19 years ago)
- Location:
- trunk/kLdr
- Files:
-
- 9 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/kLdr/Makefile.kmk
r2859 r2861 41 41 TEMPLATE_TST_ASFLAGS = -f win 42 42 TEMPLATE_TST_DEFS = __WIN__ 43 TEMPLATE_TST_SDKS = WIN32SDK 44 # kLdr_SDKS.x86 = WIN32SDK45 # kLdr_SDKS.amd64 = WIN64SDK43 TEMPLATE_TST_SDKS = WIN32SDK W2K3DDKX86 44 #TEMPLATE_SDKS.x86 = WIN32SDK W2K3DDKX86 45 #TEMPLATE_SDKS.amd64 = WIN64SDK W2K3DDKAMD64 46 46 47 47 ## @todo this is a kBuild bug! … … 77 77 kLdr_LDFLAGS = -Entry:DllMain@12 -Debug 78 78 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 82 84 kLdr_LIBS = \ 83 $$(PATH_TOOL_VCC70_LIB)/LIBC.lib 85 $$(PATH_TOOL_VCC70_LIB)/LIBC.lib \ 86 $(PATH_SDK_W2K3DDKX86_LIB)/ntdll.lib 84 87 else 85 88 ifneq ($(filter os2,$(BUILD_TARGET)),) -
trunk/kLdr/kLdr-win.def
r2858 r2861 39 39 kLdrRdrName 40 40 kLdrRdrPageSize 41 kLdrRdrPrepare42 41 kLdrRdrMap 43 kLdrRdrRefresh Map42 kLdrRdrRefresh 44 43 kLdrRdrProtect 45 44 kLdrRdrUnmap 46 kLdrRdrUnprepare47 45 kLdrRdrDone 48 46 -
trunk/kLdr/kLdr.h
r2859 r2861 87 87 # define PRI_KLDRSIZE "llx" 88 88 #endif 89 90 /** Pointer to a loader segment. */ 91 typedef struct KLDRSEG *PKLDRSEG; 92 /** Pointer to a loader segment. */ 93 typedef const struct KLDRSEG *PCKLDRSEG; 94 89 95 90 96 … … 167 173 /** @copydoc kLdrRdrPageSize */ 168 174 size_t (* pfnPageSize)(PKLDRRDR pRdr); 169 /** @copydoc kLdrRdrPrepare */170 int (* pfnPrepare)(PKLDRRDR pRdr, void **ppv, size_t cb, unsigned fFixed);171 175 /** @copydoc kLdrRdrMap */ 172 int (* pfnMap)( PKLDRRDR pRdr, void *pv, size_t cb, KLDRPROT enmProt, off_t offFile, size_t cbFile);173 /** @copydoc kLdrRdrRefresh Map*/174 int (* pfnRefresh Map)(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); 175 179 /** @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); 177 181 /** @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); 181 183 /** @copydoc kLdrRdrDone */ 182 void (* pfnDone)( PKLDRRDR pRdr);184 void (* pfnDone)( PKLDRRDR pRdr); 183 185 /** The usual non-zero dummy that makes sure we've initialized all members. */ 184 186 uint32_t u32Dummy; … … 215 217 const char *kLdrRdrName(PKLDRRDR pRdr); 216 218 size_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); 219 int kLdrRdrMap( PKLDRRDR pRdr, void **ppvBase, uint32_t cSegments, PCKLDRSEG paSegments, unsigned fFixed); 220 int kLdrRdrRefresh( PKLDRRDR pRdr, void *pvBase, uint32_t cSegments, PCKLDRSEG paSegments); 221 int kLdrRdrProtect( PKLDRRDR pRdr, void *pvBase, uint32_t cSegments, PCKLDRSEG paSegments, unsigned fUnprotectOrProtect); 222 int kLdrRdrUnmap( PKLDRRDR pRdr, void *pvBase, uint32_t cSegments, PCKLDRSEG paSegments); 223 223 void kLdrRdrDone( PKLDRRDR pRdr); 224 224 … … 430 430 uintptr_t MapAddress; 431 431 } KLDRSEG; 432 /** Pointer to a loader segment. */433 typedef KLDRSEG *PKLDRSEG;434 /** Pointer to a loader segment. */435 typedef const KLDRSEG *PCKLDRSEG;436 432 437 433 … … 1029 1025 /** Thread attach failed. */ 1030 1026 #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) 1031 1029 1032 1030 -
trunk/kLdr/kLdrHlp.c
r2854 r2861 241 241 242 242 *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); 248 247 return rc; 249 248 -
trunk/kLdr/kLdrHlp.h
r2858 r2861 34 34 35 35 /** 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)) 37 37 /** 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)) 39 39 /** Calculate the offset of a structure member. */ 40 40 #define KLDR_OFFSETOF(strct, memb) ( (size_t)( &((strct *)0)->memb ) ) … … 43 43 /** Align a void * value. */ 44 44 #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 45 48 /** @def KLDRHLP_LE2H_U16 46 49 * Unsigned 16-bit little-endian to host translation. */ -
trunk/kLdr/kLdrModPE.c
r2860 r2861 113 113 static int kldrModPEDoForwarderQuery(PKLDRMODPE pModPE, const void *pvBits, const char *pszForwarder, 114 114 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);117 115 static int kldrModPEDoFixups(PKLDRMODPE pModPE, void *pvMapping, KLDRADDR NewBaseAddress, KLDRADDR OldBaseAddress); 118 116 static int kldrModPEDoImports32Bit(PKLDRMODPE pModPE, void *pvMapping, const IMAGE_IMPORT_DESCRIPTOR *pImpDesc, … … 554 552 unsigned fFixed; 555 553 void *pvBase; 556 size_t cb;557 554 int rc; 558 555 uint32_t i; 559 556 560 557 /* 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 */ 568 560 /* fixed image? */ 569 561 fFixed = fForReal … … 580 572 581 573 /* try do the prepare */ 582 rc = kLdrRdr Prepare(pMod->pRdr, &pvBase, cb, fFixed);574 rc = kLdrRdrMap(pMod->pRdr, &pvBase, pMod->cSegments, pMod->aSegments, fFixed); 583 575 if (rc) 584 576 return rc; 585 577 586 578 /* 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++) 600 584 { 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; 611 587 } 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; 621 589 } 622 590 else 623 kLdrRdrUnprepare(pMod->pRdr, pvBase, cb);624 return rc;591 pModPE->pvBits = pvBase; 592 return 0; 625 593 } 626 594 … … 640 608 PKLDRMOD pMod = pModPE->pMod; 641 609 size_t cb = (size_t)pMod->pOps->pfnSize(pModPE->pMod); 642 int rc2; 643 int rc = 0; 610 int rc; 644 611 uint32_t i; 645 612 646 613 /* 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++) 656 627 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; 677 633 } 678 634 … … 717 673 else 718 674 { 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; 721 681 } 722 682 } … … 1336 1296 static int kldrModPEReload(PKLDRMOD pMod) 1337 1297 { 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; 1342 1299 1343 1300 /* … … 1347 1304 return KLDR_ERR_NOT_MAPPED; 1348 1305 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); 1360 1308 } 1361 1309 … … 1376 1324 * Before doing anything we'll have to make all pages writable. 1377 1325 */ 1378 rc = k ldrModPEUnprotect(pModPE, pModPE->pvMapping);1326 rc = kLdrRdrProtect(pMod->pRdr, (void *)pModPE->pvMapping, pMod->cSegments, pMod->aSegments, 1 /* unprotect */); 1379 1327 if (rc) 1380 1328 return rc; … … 1395 1343 * Restore protection. 1396 1344 */ 1397 rc2 = k ldrModPEProtect(pModPE, pModPE->pvMapping);1345 rc2 = kLdrRdrProtect(pMod->pRdr, (void *)pModPE->pvMapping, pMod->cSegments, pMod->aSegments, 0 /* protect */); 1398 1346 if (!rc && rc2) 1399 1347 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 1509 1348 return rc; 1510 1349 } -
trunk/kLdr/kLdrRdr.c
r2856 r2861 223 223 224 224 /** 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 */ 238 int 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 */ 254 int 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 */ 275 int 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 */ 291 int kLdrRdrUnmap(PKLDRRDR pRdr, void *pvBase, uint32_t cSegments, PCKLDRSEG paSegments) 292 { 293 KLDRRDR_VALIDATE(pRdr); 294 return pRdr->pOps->pfnUnmap(pRdr, pvBase, cSegments, paSegments); 328 295 } 329 296 -
trunk/kLdr/kLdrRdrFile.c
r2860 r2861 35 35 36 36 #elif defined(__WIN32__) || defined(__WIN64__) || defined(__WIN__) 37 # define WIN32_NO_STATUS 37 38 # include <Windows.h> 38 39 # ifndef __WIN__ 39 40 # define __WIN__ 40 41 # 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 ); 41 149 42 150 #else … … 46 154 #include <kLdr.h> 47 155 #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 48 173 49 174 … … 102 227 *******************************************************************************/ 103 228 static 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); 229 static int kldrRdrFileUnmap(PKLDRRDR pRdr, void *pvBase, uint32_t cSegments, PCKLDRSEG paSegments); 230 static int kldrRdrFileGenericUnmap(PKLDRRDR pRdr, PKLDRRDRFILEPREP pPrep, uint32_t cSegments, PCKLDRSEG paSegments); 231 static int kldrRdrFileProtect(PKLDRRDR pRdr, void *pvBase, uint32_t cSegments, PCKLDRSEG paSegments, unsigned fUnprotectOrProtect); 232 static int kldrRdrFileGenericProtect(PKLDRRDR pRdr, PKLDRRDRFILEPREP pPrep, uint32_t cSegments, PCKLDRSEG paSegments, unsigned fUnprotectOrProtect); 233 static int kldrRdrFileRefresh(PKLDRRDR pRdr, void *pvBase, uint32_t cSegments, PCKLDRSEG paSegments); 234 static int kldrRdrFileGenericRefresh(PKLDRRDR pRdr, PKLDRRDRFILEPREP pPrep, uint32_t cSegments, PCKLDRSEG paSegments); 235 static int kldrRdrFileMap(PKLDRRDR pRdr, void *ppvBase, uint32_t cSegments, PCKLDRSEG paSegments, unsigned fFixed); 236 static int kldrRdrFileGenericMap(PKLDRRDR pRdr, PKLDRRDRFILEPREP pPrep, uint32_t cSegments, PCKLDRSEG paSegments, unsigned fFixed); 110 237 static size_t kldrRdrFilePageSize(PKLDRRDR pRdr); 111 238 static const char *kldrRdrFileName(PKLDRRDR pRdr); … … 136 263 kldrRdrFileName, 137 264 kldrRdrFilePageSize, 138 kldrRdrFilePrepare,139 265 kldrRdrFileMap, 140 kldrRdrFileRefresh Map,266 kldrRdrFileRefresh, 141 267 kldrRdrFileProtect, 142 268 kldrRdrFileUnmap, 143 kldrRdrFileUnprepare,144 269 kldrRdrFileDone, 145 270 42 146 271 }; 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 */ 281 static 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 */ 304 static 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 147 320 148 321 … … 159 332 * @param pFile The instance data. 160 333 * @param pv The base of the region. 161 * @param cb The size of the region.162 334 */ 163 static PKLDRRDRFILEPREP kldrRdrFileFindPrepExact(PKLDRRDRFILE pFile, void *pv , size_t cb)335 static PKLDRRDRFILEPREP kldrRdrFileFindPrepExact(PKLDRRDRFILE pFile, void *pv) 164 336 { 165 337 int32_t i = pFile->cPreps; 166 338 while (i-- > 0) 167 if ( pFile->aPreps[i].pv == pv 168 || pFile->aPreps[i].cb == cb) 339 if (pFile->aPreps[i].pv == pv) 169 340 return &pFile->aPreps[i]; 170 341 return NULL; … … 172 343 173 344 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 */ 346 static int kldrRdrFileUnmap(PKLDRRDR pRdr, void *pvBase, uint32_t cSegments, PCKLDRSEG paSegments) 198 347 { 199 348 PKLDRRDRFILE pRdrFile = (PKLDRRDRFILE)pRdr; 200 PKLDRRDRFILEPREP pPrep = kldrRdrFileFindPrepExact(pRdrFile, pv, cb); 349 PKLDRRDRFILEPREP pPrep = kldrRdrFileFindPrepExact(pRdrFile, pvBase); 350 int rc; 201 351 if (!pPrep) 202 352 return KLDR_ERR_INVALID_PARAMETER; 203 353 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. */ 376 static 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 */ 384 static int kldrRdrFileProtect(PKLDRRDR pRdr, void *pvBase, uint32_t cSegments, PCKLDRSEG paSegments, unsigned fUnprotectOrProtect) 210 385 { 211 386 PKLDRRDRFILE pRdrFile = (PKLDRRDRFILE)pRdr; 212 PKLDRRDRFILEPREP pPrep = kldrRdrFileFindPrepExact(pRdrFile, pv , cb);387 PKLDRRDRFILEPREP pPrep = kldrRdrFileFindPrepExact(pRdrFile, pvBase); 213 388 if (!pPrep) 214 389 return KLDR_ERR_INVALID_PARAMETER; 215 390 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. */ 404 static 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 */ 464 static int kldrRdrFileRefresh(PKLDRRDR pRdr, void *pvBase, uint32_t cSegments, PCKLDRSEG paSegments) 222 465 { 223 466 PKLDRRDRFILE pRdrFile = (PKLDRRDRFILE)pRdr; 224 PKLDRRDRFILEPREP pPrep = kldrRdrFileFindPrepExact(pRdrFile, pv , cb);467 PKLDRRDRFILEPREP pPrep = kldrRdrFileFindPrepExact(pRdrFile, pvBase); 225 468 if (!pPrep) 226 469 return KLDR_ERR_INVALID_PARAMETER; 227 470 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. */ 484 static 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 */ 537 static int kldrRdrFileMap(PKLDRRDR pRdr, void **ppvBase, uint32_t cSegments, PCKLDRSEG paSegments, unsigned fFixed) 234 538 { 235 539 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. */ 765 static 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; 268 808 } 269 809 … … 572 1112 SecAttr.lpSecurityDescriptor = NULL; 573 1113 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); 575 1115 if (File == INVALID_HANDLE_VALUE) 576 1116 return GetLastError(); -
trunk/kLdr/tstkLdrMod.c
r2860 r2861 40 40 *******************************************************************************/ 41 41 /** The default base address used in the tests. */ 42 #define MY_BASEADDRESS 0x 420000042 #define MY_BASEADDRESS 0x2400000 43 43 44 44 … … 69 69 70 70 71 /** Dummy import resolver callback. */ 72 static 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 */ 85 static 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 71 176 /** 72 177 * Dump symbols and check that we can query each of them recursivly. … … 91 196 &uValue2, &fKind2); 92 197 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); 94 199 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", 96 201 iSymbol, pszSymbol, uValue, uValue2, pvUser); 97 202 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", 99 204 iSymbol, pszSymbol, fKind, fKind2, pvUser); 100 205 } … … 106 211 &uValue2, &fKind2); 107 212 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); 109 214 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", 111 216 iSymbol, pszSymbol, uValue, uValue2, pvUser); 112 217 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", 114 219 iSymbol, pszSymbol, fKind, fKind2, pvUser); 115 220 } … … 153 258 KLDRSTACKINFO StackInfo; 154 259 260 printf("* Testing queries with pvBits=%p...\n", pvBits); 261 155 262 /* 156 263 * Get the import modules. … … 159 266 printf("cImports=%d\n", cImports); 160 267 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); 162 269 for (i = 0; i < cImports; i++) 163 270 { … … 201 308 if (MainEPAddress == ~(KLDRADDR)42) 202 309 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)."); 203 314 204 315 /* … … 256 367 */ 257 368 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;268 369 return 0; 269 370 } … … 354 455 } 355 456 457 356 458 /* 357 459 * Get image the size and query the image bits. 358 460 */ 461 printf("* Testing user mapping...\n"); 462 359 463 cbImage = (size_t)kLdrModSize(pMod); 360 464 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!"); 362 466 pvBits = malloc((size_t)cbImage); 363 467 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); 365 469 366 470 rc = kLdrModGetBits(pMod, pvBits, (uintptr_t)pvBits, BasicTestsGetImport, NULL); 367 471 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); 369 473 370 474 /* … … 372 476 */ 373 477 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 374 493 free(pvBits); 375 494 return rc; … … 378 497 379 498 /** 499 * Tests the mapping related api, after mapping. 500 */ 501 static 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 /** 380 543 * Tests the mapping related api. 381 544 */ 382 545 static int BasicTestsSubMap(PKLDRMOD pMod) 383 546 { 384 int rc; 547 int rc, rc2; 548 printf("* Mapping tests...\n"); 385 549 386 550 rc = kLdrModMap(pMod); 387 551 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; 391 563 } 392 564 … … 400 572 int rc, rc2; 401 573 402 printf("tstLdrMod: Testing '%s' \n", pszFilename);574 printf("tstLdrMod: Testing '%s'", pszFilename); 403 575 rc = kLdrModOpen(pszFilename, &pMod); 404 576 if (!rc) … … 407 579 if (!rc) 408 580 rc = BasicTestsSubMap(pMod); 581 if (!rc) 582 rc = BasicTestsSub2(pMod, NULL); 409 583 rc2 = kLdrModClose(pMod); 410 584 if (rc2) 411 Failure("failed to close '%s', rc=%d \n", pszFilename, rc);585 Failure("failed to close '%s', rc=%d", pszFilename, rc); 412 586 if (rc2 && !rc) 413 587 rc = rc2; 414 588 } 415 589 else 416 Failure("Failed to open '%s', rc=%d \n", pszFilename, rc);590 Failure("Failed to open '%s', rc=%d", pszFilename, rc); 417 591 return rc ? 1 : 0; 418 592 }
Note:
See TracChangeset
for help on using the changeset viewer.