Changeset 2882 for trunk/kLdr/kLdrModLX.c
- Timestamp:
- Nov 16, 2006, 6:52:27 AM (19 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/kLdr/kLdrModLX.c
r2880 r2882 117 117 PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser); 118 118 static int kldrModLXDoCreate(PKLDRRDR pRdr, off_t offNewHdr, PKLDRMODLX *ppModLX); 119 static const uint8_t *kldrModLXDoNameTableLookupByOrdinal(const uint8_t *pbNameTable, int32_t cbNameTable, uint32_t iOrdinal); 120 static int kldrModLXDoNameLookup(PKLDRMODLX pModLX, const char *pszSymbol, uint32_t *piSymbol); 121 static const uint8_t *kldrModLXDoNameTableLookupByName(const uint8_t *pbNameTable, int32_t cbNameTable, 122 char *pchSymbol, size_t cchSymbol); 119 123 static int kldrModLXDoLoadBits(PKLDRMODLX pModLX, void *pvBits); 120 124 static int kldrModLXDoIterDataUnpacking(uint8_t *pbDst, const uint8_t *pbSrc, int cbSrc); … … 123 127 static int kldrModLXDoProtect(PKLDRMODLX pModLX, void *pvBits, unsigned fUnprotectOrProtect); 124 128 static int kldrModLXDoCallDLL(PKLDRMODLX pModLX, unsigned uOp, uintptr_t uHandle); 129 static int32_t kldrModLXDoGetOrdinalByName(PKLDRMODLX pModLX, const char *pszName); 130 static int kldrModLXDoForwarderQuery(PKLDRMODLX pModLX, const struct e32_entry *pEntry, 131 PFNKLDRMODGETIMPORT pfnGetForwarder, void *pvUser, PKLDRADDR puValue, uint32_t *pfKind); 132 static int kldrModLXDoLoadFixupSection(PKLDRMODLX pModLX); 125 133 static int32_t kldrModLXDoCall(uintptr_t uEntrypoint, uintptr_t uHandle, uint32_t uOp, void *pvReserved); 126 134 … … 355 363 /* 356 364 * Get the soname from the resident name table. 357 */ 358 /** @todo */ 365 * Very convenient that it's the 0 ordinal, because then we get a 366 * free string terminator. 367 * (The table entry consists of a pascal string followed by a 16-bit ordinal.) 368 */ 369 pMod->pszName = kldrModLXDoNameTableLookupByOrdinal(pModLX->pbResNameTab, 370 pModLX->pbLoaderSectionLast - pModLX->pbResNameTab + 1, 371 0); 372 if (!pMod->pszName) 373 return KLDR_ERR_LX_NO_SONAME; 374 pMod->cchName = *(const uint8_t *)pMod->pszName++; 375 if (pMod->cchName != kLdrHlpStrLen(pMod->pszName)) 376 return KLDR_ERR_LX_BAD_SONAME; 359 377 360 378 /* … … 484 502 pModLX->pbFixupSection = NULL; 485 503 } 486 if (pMod->pszName)487 {488 kldrHlpFree((void *)pMod->pszName);489 pMod->pszName = NULL;490 }491 504 pMod->u32Magic = 0; 492 505 pMod->pOps = NULL; … … 516 529 PKLDRADDR puValue, uint32_t *pfKind) 517 530 { 518 PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData; 519 //int rc; 520 521 kldrModLXResolveBaseAddress(pModLX, &BaseAddress); 522 531 PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData; 532 uint32_t iOrdinal; 533 int rc; 534 const struct b32_bundle *pBundle; 535 536 537 /* 538 * Give up at once if there is no entry table. 539 */ 540 if (!pModLX->Hdr.e32_enttab) 541 return KLDR_ERR_SYMBOL_NOT_FOUND; 542 543 /* 544 * Translate the symbol name into an ordinal. 545 */ 546 if (pszSymbol) 547 { 548 rc = kldrModLXDoNameLookup(pModLX, pszSymbol, &iSymbol); 549 if (rc) 550 return rc; 551 } 552 553 /* 554 * Iterate the entry table. 555 * (The entry table is made up of bundles of similar exports.) 556 */ 557 iOrdinal = 0; 558 pBundle = (const struct b32_bundle *)pModLX->pbEntryTab; 559 while (!pBundle->b32_cnt && iOrdinal <= iSymbol) 560 { 561 static const size_t s_cbEntry[] = { 0, 3, 5, 5, 7 }; 562 563 /* 564 * Check for a hit first. 565 */ 566 iOrdinal += pBundle->b32_cnt; 567 if (iSymbol < iOrdinal) 568 { 569 uint32_t offObject; 570 const struct e32_entry *pEntry = (const struct e32_entry *)((uintptr_t)(pBundle + 1) 571 + iSymbol - (iOrdinal - pBundle->b32_cnt)); 572 573 /* 574 * Calculate the return address. 575 */ 576 kldrModLXResolveBaseAddress(pModLX, &BaseAddress); 577 switch (pBundle->b32_type) 578 { 579 /* empty bundles are place holders unused ordinal ranges. */ 580 case EMPTY: 581 return KLDR_ERR_SYMBOL_NOT_FOUND; 582 583 /* e32_flags + a 16-bit offset. */ 584 case ENTRY16: 585 offObject = pEntry->e32_variant.e32_offset.offset16; 586 if (pfKind) 587 *pfKind = KLDRSYMKIND_16BIT | KLDRSYMKIND_NO_TYPE; 588 break; 589 590 /* e32_flags + a 16-bit offset + a 16-bit callgate selector. */ 591 case GATE16: 592 offObject = pEntry->e32_variant.e32_callgate.offset; 593 if (pfKind) 594 *pfKind = KLDRSYMKIND_16BIT | KLDRSYMKIND_CODE; 595 break; 596 597 /* e32_flags + a 32-bit offset. */ 598 case ENTRY32: 599 offObject = pEntry->e32_variant.e32_offset.offset32; 600 if (pfKind) 601 *pfKind = KLDRSYMKIND_32BIT; 602 break; 603 604 /* e32_flags + 16-bit import module ordinal + a 32-bit procname or ordinal. */ 605 case ENTRYFWD: 606 return kldrModLXDoForwarderQuery(pModLX, pEntry, pfnGetForwarder, pvUser, puValue, pfKind); 607 608 default: 609 /* anyone actually using TYPEINFO will end up here. */ 610 KLDRMODLX_ASSERT(!"Bad bundle type"); 611 break; 612 } 613 614 /* 615 * Validate the object number and calc the return address. 616 */ 617 if ( pBundle->b32_obj <= 0 618 || pBundle->b32_obj > pMod->cSegments) 619 return KLDR_ERR_LX_BAD_BUNDLE; 620 if (puValue) 621 *puValue = BaseAddress 622 + offObject 623 + pMod->aSegments[pBundle->b32_obj - 1].RVA; 624 return 0; 625 } 626 627 /* 628 * Skip the bundle. 629 */ 630 if (pBundle->b32_type > ENTRYFWD) 631 { 632 KLDRMODLX_ASSERT(!"Bad type"); /** @todo figure out TYPEINFO. */ 633 return KLDR_ERR_LX_BAD_BUNDLE; 634 } 635 if (pBundle->b32_type == 0) 636 pBundle = (const struct b32_bundle *)((const uint8_t *)pBundle + 2); 637 else 638 pBundle = (const struct b32_bundle *)((const uint8_t *)pBundle + s_cbEntry[pBundle->b32_type] * pBundle->b32_cnt); 639 } 640 641 return KLDR_ERR_SYMBOL_NOT_FOUND; 642 } 643 644 645 /** 646 * Do name lookup. 647 * 648 * @returns See kLdrModQuerySymbol. 649 * @param pModLX The module to lookup the symbol in. 650 * @param pszSymbol The symbol to lookup. 651 * @param piSymbol Where to store the symbol ordinal. 652 */ 653 static int kldrModLXDoNameLookup(PKLDRMODLX pModLX, const char *pszSymbol, uint32_t *piSymbol) 654 { 655 656 /* 657 * First do a hash table lookup. 658 */ 659 660 661 662 /* 663 664 */ 665 666 return -1; 667 } 668 669 670 /** 671 * Hash a symbol using the algorithm from sdbm. 672 * 673 * The following was is the documenation of the orignal sdbm functions: 674 * 675 * This algorithm was created for sdbm (a public-domain reimplementation of 676 * ndbm) database library. it was found to do well in scrambling bits, 677 * causing better distribution of the keys and fewer splits. it also happens 678 * to be a good general hashing function with good distribution. the actual 679 * function is hash(i) = hash(i - 1) * 65599 + str[i]; what is included below 680 * is the faster version used in gawk. [there is even a faster, duff-device 681 * version] the magic constant 65599 was picked out of thin air while 682 * experimenting with different constants, and turns out to be a prime. 683 * this is one of the algorithms used in berkeley db (see sleepycat) and 684 * elsewhere. 685 */ 686 static uint32_t kldrModLXDoHash(const char *pchSymbol, uint8_t cchSymbol) 687 { 688 uint32_t hash = 0; 689 int ch; 690 691 while ( cchSymbol-- > 0 692 && (ch = *(unsigned const char *)pchSymbol++)) 693 hash = ch + (hash << 6) + (hash << 16) - hash; 694 695 return hash; 696 } 697 698 699 /** 700 * Lookup a name table entry by name. 701 * 702 * @returns Pointer to the name table entry if found. 703 * @returns NULL if not found. 704 * @param pbNameTable Pointer to the name table that should be searched. 705 * @param cbNameTable The size of the name table. 706 * @param pchSymbol The name of the symbol we're looking for. 707 * @param cchSymbol The length of the symbol name. 708 */ 709 static const uint8_t *kldrModLXDoNameTableLookupByName(const uint8_t *pbNameTable, int32_t cbNameTable, 710 char *pchSymbol, size_t cchSymbol) 711 { 712 /* 713 * Determin the namelength up front so we can skip anything which doesn't matches the length. 714 */ 715 uint8_t cbSymbol8Bit = (uint8_t)cchSymbol; 716 if (cbSymbol8Bit != cchSymbol) 717 return NULL; /* too long. */ 718 719 /* 720 * Walk the name table. 721 */ 722 while (*pbNameTable != 0 && cbNameTable > 0) 723 { 724 const uint8_t cbName = *pbNameTable; 725 726 cbNameTable -= cbName + 1 + 2; 727 if (cbNameTable < 0) 728 break; 729 730 if ( cbName == cbSymbol8Bit 731 && !kLdrHlpMemComp(pbNameTable + 1, pchSymbol, cbName)) 732 return pbNameTable; 733 734 /* next entry */ 735 pbNameTable += cbName + 1 + 2; 736 } 737 738 return NULL; 739 } 740 741 742 /** 743 * Deal with a forwarder entry. 744 * 745 * @returns See kLdrModQuerySymbol. 746 * @param pModLX The PE module interpreter instance. 747 * @param pEntry The forwarder entry. 748 * @param pfnGetForwarder The callback for resolving forwarder symbols. (optional) 749 * @param pvUser The user argument for the callback. 750 * @param puValue Where to put the value. (optional) 751 * @param pfKind Where to put the symbol kind. (optional) 752 */ 753 static int kldrModLXDoForwarderQuery(PKLDRMODLX pModLX, const struct e32_entry *pEntry, 754 PFNKLDRMODGETIMPORT pfnGetForwarder, void *pvUser, PKLDRADDR puValue, uint32_t *pfKind) 755 { 756 int rc; 757 uint32_t iSymbol; 758 const char *pszSymbol; 759 760 if (!pfnGetForwarder) 761 return KLDR_ERR_FORWARDER_SYMBOL; 762 763 /* 764 * Validate the entry import module ordinal. 765 */ 766 if ( !pEntry->e32_variant.e32_fwd.modord 767 || pEntry->e32_variant.e32_fwd.modord > pModLX->Hdr.e32_impmodcnt) 768 return KLDR_ERR_LX_BAD_FORWARDER; 769 770 /* 771 * Figure out the parameters. 772 */ 773 if (pEntry->e32_flags & FWD_ORDINAL) 774 { 775 iSymbol = pEntry->e32_variant.e32_fwd.value; 776 pszSymbol = NULL; /* no symbol name. */ 777 } 778 else 779 { 780 const uint8_t *pbName; 781 782 /* load the fixup section if necessary. */ 783 if (!pModLX->pbImportProcs) 784 { 785 rc = kldrModLXDoLoadFixupSection(pModLX); 786 if (rc) 787 return rc; 788 } 789 790 /* Make name pointer. */ 791 pbName = pModLX->pbImportProcs + pEntry->e32_variant.e32_fwd.value; 792 if ( pbName >= pModLX->pbFixupSectionLast 793 || pbName < pModLX->pbFixupSectionLast 794 || !*pbName) 795 return KLDR_ERR_LX_BAD_FORWARDER; 796 797 798 /* check for '#' name. */ 799 if (pbName[1] == '#') 800 { 801 uint8_t cbLeft = *pbName; 802 const uint8_t *pb = pbName + 1; 803 unsigned uBase; 804 805 /* base detection */ 806 uBase = 10; 807 if ( cbLeft > 1 808 && pb[1] == '0' 809 && (pb[2] == 'x' || pb[2] == 'X')) 810 { 811 uBase = 16; 812 pb += 2; 813 cbLeft -= 2; 814 } 815 816 /* ascii to integer */ 817 iSymbol = 0; 818 while (cbLeft-- > 0) 819 { 820 /* convert char to digit. */ 821 unsigned uDigit = *pb++; 822 if (uDigit >= '0' && uDigit <= '9') 823 uDigit -= '0'; 824 else if (uDigit >= 'a' && uDigit <= 'z') 825 uDigit -= 'a' + 10; 826 else if (uDigit >= 'A' && uDigit <= 'Z') 827 uDigit -= 'A' + 10; 828 else if (!uDigit) 829 break; 830 else 831 return KLDR_ERR_LX_BAD_FORWARDER; 832 if (uDigit >= uBase) 833 return KLDR_ERR_LX_BAD_FORWARDER; 834 835 /* insert the digit */ 836 iSymbol *= uBase; 837 iSymbol += uDigit; 838 } 839 if (!iSymbol) 840 return KLDR_ERR_LX_BAD_FORWARDER; 841 842 pszSymbol = NULL; /* no symbol name. */ 843 } 844 else 845 { 846 /* Make a stack copy of the name that's zero terminated. */ 847 char *pszCopy = kLdrHlpAllocA(*pbName + 1); 848 kLdrHlpMemCopy(pszCopy, pbName + 1, *pbName); 849 pszCopy[*pbName] = '\0'; 850 851 pszSymbol = pszCopy; 852 iSymbol = NIL_KLDRMOD_SYM_ORDINAL; 853 } 854 } 855 856 /* 857 * Resolve the forwarder. 858 */ 859 rc = pfnGetForwarder(pModLX->pMod, pEntry->e32_variant.e32_fwd.modord - 1, iSymbol, pszSymbol, puValue, pfKind, pvUser); 860 if (!rc && pfKind) 861 *pfKind |= KLDRSYMKIND_FORWARDER; 862 return rc; 863 } 864 865 866 /** 867 * Loads the fixup section from the executable image. 868 * 869 * The fixup section isn't loaded until it's accessed. It's also freed by kLdrModDone(). 870 * 871 * @returns 0 on success, non-zero kLdr or native status code on failure. 872 * @param pModLX The PE module interpreter instance. 873 */ 874 static int kldrModLXDoLoadFixupSection(PKLDRMODLX pModLX) 875 { 523 876 return -1; 524 877 } … … 535 888 536 889 return -1; 890 } 891 892 893 /** 894 * Lookup a name table entry by ordinal. 895 * 896 * @returns Pointer to the name table entry if found. 897 * @returns NULL if not found. 898 * @param pbNameTable Pointer to the name table that should be searched. 899 * @param cbNameTable The size of the name table. 900 * @param iOrdinal The ordinal to search for. 901 */ 902 static const uint8_t *kldrModLXDoNameTableLookupByOrdinal(const uint8_t *pbNameTable, int32_t cbNameTable, uint32_t iOrdinal) 903 { 904 while (*pbNameTable != 0 && cbNameTable > 0) 905 { 906 const uint8_t cbName = *pbNameTable; 907 uint32_t iName; 908 909 cbNameTable -= cbName + 1 + 2; 910 if (cbNameTable < 0) 911 break; 912 913 iName = *(pbNameTable + cbName) 914 | ((unsigned)*(pbNameTable + cbName + 1) << 8); 915 if (iName == iOrdinal) 916 return pbNameTable; 917 918 /* next entry */ 919 pbNameTable += cbName + 1 + 2; 920 } 921 922 return NULL; 537 923 } 538 924 … … 1153 1539 * protect according to the object table. 1154 1540 */ 1155 static int kldrModLXDoProtect(PKLDRMODLX pMod, void *pvBits, unsigned fUnprotectOrProtect) 1156 { 1157 return -1; 1541 static int kldrModLXDoProtect(PKLDRMODLX pModLX, void *pvBits, unsigned fUnprotectOrProtect) 1542 { 1543 uint32_t i; 1544 PKLDRMOD pMod = pModLX->pMod; 1545 1546 /* 1547 * Change object protection. 1548 */ 1549 for (i = 0; i < pMod->cSegments; i++) 1550 { 1551 int rc; 1552 void *pv; 1553 KLDRPROT enmProt; 1554 1555 /* calc new protection. */ 1556 enmProt = pMod->aSegments[i].enmProt; 1557 if (fUnprotectOrProtect) 1558 { 1559 switch (enmProt) 1560 { 1561 case KLDRPROT_NOACCESS: 1562 case KLDRPROT_READONLY: 1563 case KLDRPROT_READWRITE: 1564 case KLDRPROT_WRITECOPY: 1565 enmProt = KLDRPROT_READWRITE; 1566 break; 1567 case KLDRPROT_EXECUTE: 1568 case KLDRPROT_EXECUTE_READ: 1569 case KLDRPROT_EXECUTE_READWRITE: 1570 case KLDRPROT_EXECUTE_WRITECOPY: 1571 enmProt = KLDRPROT_EXECUTE_READWRITE; 1572 break; 1573 default: 1574 KLDRMODLX_ASSERT(!"bad enmProt"); 1575 return -1; 1576 } 1577 } 1578 else 1579 { 1580 /* copy on write -> normal write. */ 1581 if (enmProt == KLDRPROT_EXECUTE_WRITECOPY) 1582 enmProt = KLDRPROT_EXECUTE_READWRITE; 1583 else if (enmProt == KLDRPROT_WRITECOPY) 1584 enmProt = KLDRPROT_READWRITE; 1585 } 1586 1587 1588 /* calc the address and set page protection. */ 1589 pv = (uint8_t *)pvBits + pMod->aSegments[i].RVA; 1590 1591 rc = kldrHlpPageProtect(pv, pMod->aSegments[i].cbMapped, enmProt); 1592 if (rc) 1593 break; 1594 1595 /** @todo the gap page should be marked NOACCESS! */ 1596 } 1597 1598 return 0; 1158 1599 } 1159 1600 … … 1191 1632 PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData; 1192 1633 1193 /* just do the error checking. */1634 /* no tls, just do the error checking. */ 1194 1635 if (!pModLX->pvMapping) 1195 1636 return KLDR_ERR_NOT_MAPPED; … … 1201 1642 static void kldrModLXFreeTLS(PKLDRMOD pMod) 1202 1643 { 1644 /* no tls. */ 1203 1645 } 1204 1646 … … 1235 1677 * Before doing anything we'll have to make all pages writable. 1236 1678 */ 1237 rc = k LdrRdrProtect(pMod->pRdr, (void *)pModLX->pvMapping, pMod->cSegments, pMod->aSegments, 1 /* unprotect */);1679 rc = kldrModLXDoProtect(pModLX, (void *)pModLX->pvMapping, 1 /* unprotect */); 1238 1680 if (rc) 1239 1681 return rc; … … 1248 1690 * Restore protection. 1249 1691 */ 1250 rc2 = k LdrRdrProtect(pMod->pRdr, (void *)pModLX->pvMapping, pMod->cSegments, pMod->aSegments, 0 /* protect */);1692 rc2 = kldrModLXDoProtect(pModLX, (void *)pModLX->pvMapping, 0 /* protect */); 1251 1693 if (!rc && rc2) 1252 1694 rc = rc2; … … 1397 1839 static int kldrModLXCallThread(PKLDRMOD pMod, uintptr_t uHandle, unsigned fAttachingOrDetaching) 1398 1840 { 1841 /* no thread attach/detach callout. */ 1399 1842 return 0; 1400 1843 }
Note:
See TracChangeset
for help on using the changeset viewer.