Ignore:
Timestamp:
Nov 12, 2006, 6:21:16 PM (19 years ago)
Author:
bird
Message:

started coding on the LX module interpreter.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/kLdr/kLdrModLX.c

    r2827 r2879  
    22/** @file
    33 *
    4  * kLdr - The Dynamic Loader, LX Image.
     4 * kLdr - The Module Interpreter for the Linear eXecutable (LX) Format.
    55 *
    66 * Copyright (c) 2006 knut st. osmundsen <bird@anduin.net>
     
    2525 */
    2626
    27 #include "kLdr.h"
    28 
     27
     28/*******************************************************************************
     29*   Header Files                                                               *
     30*******************************************************************************/
     31#include <kLdr.h>
     32#include "kLdrHlp.h"
     33#include "kLdrInternal.h"
     34#include "kLdrModLX.h"
     35
     36
     37/*******************************************************************************
     38*   Defined Constants And Macros                                               *
     39*******************************************************************************/
     40/** @def KLDRMODLX_STRICT
     41 * Define KLDRMODLX_STRICT to enabled strict checks in KLDRMODLX. */
     42#define KLDRMODLX_STRICT 1
     43
     44/** @def KLDRMODLX_ASSERT
     45 * Assert that an expression is true when KLDR_STRICT is defined.
     46 */
     47#ifdef KLDRMODLX_STRICT
     48# define KLDRMODLX_ASSERT(expr)  kldrHlpAssert(expr)
     49#else
     50# define KLDRMODLX_ASSERT(expr)  do {} while (0)
     51#endif
     52
     53
     54/*******************************************************************************
     55*   Structures and Typedefs                                                    *
     56*******************************************************************************/
     57/**
     58 * Instance data for the LX module interpreter.
     59 */
     60typedef struct KLDRMODLX
     61{
     62    /** Pointer to the module. (Follows the section table.) */
     63    PKLDRMOD                pMod;
     64    /** Pointer to the user mapping. */
     65    const void             *pvMapping;
     66    /** The size of the mapped LX image. */
     67    size_t                  cbMapped;
     68    /** Reserved flags. */
     69    uint32_t                f32Reserved;
     70
     71    /** The offset of the LX header. */
     72    off_t                   offHdr;
     73    /** Copy of the LX header. */
     74    struct e32_exe          Hdr;
     75
     76    /** Pointer to the loader section.
     77     * Allocated together with this strcture. */
     78    const uint8_t          *pbLoaderSection;
     79    /** Pointer to the last byte in the loader section. */
     80    const uint8_t          *pbLoaderSectionLast;
     81    /** Pointer to the object table in the loader section. */
     82    const struct o32_obj   *paObjs;
     83    /** Pointer to the object page map table in the loader section. */
     84    const struct o32_map   *paPageMappings;
     85    /** Pointer to the resource table in the loader section. */
     86    const struct rsrc32    *paRsrcs;
     87    /** Pointer to the resident name table in the loader section. */
     88    const uint8_t          *pbResNameTab;
     89    /** Pointer to the entry table in the loader section. */
     90    const uint8_t          *pbEntryTab;
     91
     92    /** Pointer to the non-resident name table. */
     93    uint8_t                *pbNonResNameTab;
     94    /** Pointer to the last byte in the non-resident name table. */
     95    const uint8_t          *pbNonResNameTabLast;
     96
     97    /** Pointer to the fixup section. */
     98    uint8_t                *pbFixupSection;
     99    /** Pointer to the last byte in the fixup section. */
     100    const uint8_t          *pbFixupSectionLast;
     101    /** Pointer to the fixup page table within pvFixupSection. */
     102    const uint32_t         *paoffPageFixups;
     103    /** Pointer to the fixup record table within pvFixupSection. */
     104    const uint8_t          *pbFixupRecs;
     105    /** Pointer to the import module name table within pvFixupSection. */
     106    const uint8_t          *pbImportMods;
     107    /** Pointer to the import module name table within pvFixupSection. */
     108    const uint8_t          *pbImportProcs;
     109} KLDRMODLX, *PKLDRMODLX;
     110
     111
     112/*******************************************************************************
     113*   Internal Functions                                                         *
     114*******************************************************************************/
     115static int kldrModLXHasDbgInfo(PKLDRMOD pMod, const void *pvBits);
     116static int kldrModLXRelocateBits(PKLDRMOD pMod, void *pvBits, KLDRADDR NewBaseAddress, KLDRADDR OldBaseAddress,
     117                                 PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser);
     118static int kldrModLXDoCreate(PKLDRRDR pRdr, off_t offNewHdr, PKLDRMODLX *ppModLX);
     119static int kldrModLXDoLoadBits(PKLDRMODLX pModLX, void *pvBits);
     120static int kldrModLXDoProtect(PKLDRMODLX pModLX, void *pvBits, unsigned fUnprotectOrProtect);
     121static int kldrModLXDoCallDLL(PKLDRMODLX pModLX, unsigned uOp, uintptr_t uHandle);
     122static int32_t kldrModLXDoCall(uintptr_t uEntrypoint, uintptr_t uHandle, uint32_t uOp, void *pvReserved);
     123
     124
     125/**
     126 * Create a loader module instance interpreting the executable image found
     127 * in the specified file provider instance.
     128 *
     129 * @returns 0 on success and *ppMod pointing to a module instance.
     130 *          On failure, a non-zero OS specific error code is returned.
     131 * @param   pOps            Pointer to the registered method table.
     132 * @param   pRdr            The file provider instance to use.
     133 * @param   offNewHdr       The offset of the new header in MZ files. -1 if not found.
     134 * @param   ppMod           Where to store the module instance pointer.
     135 */
     136static int kldrModLXCreate(PCKLDRMODOPS pOps, PKLDRRDR pRdr, off_t offNewHdr, PPKLDRMOD ppMod)
     137{
     138    PKLDRMODLX pModLX;
     139    int rc;
     140
     141    /*
     142     * Create the instance data and do a minimal header validation.
     143     */
     144    rc = kldrModLXDoCreate(pRdr, offNewHdr, &pModLX);
     145    if (!rc)
     146    {
     147        pModLX->pMod->pOps = pOps;
     148        pModLX->pMod->u32Magic = KLDRMOD_MAGIC;
     149        *ppMod = pModLX->pMod;
     150        return 0;
     151    }
     152    kldrHlpFree(pModLX);
     153    return rc;
     154}
     155
     156
     157/**
     158 * Separate function for reading creating the LX module instance to
     159 * simplify cleanup on failure.
     160 */
     161static int kldrModLXDoCreate(PKLDRRDR pRdr, off_t offNewHdr, PKLDRMODLX *ppModLX)
     162{
     163    struct e32_exe Hdr;
     164    PKLDRMODLX pModLX;
     165    PKLDRMOD pMod;
     166    size_t cb;
     167    size_t cchFilename;
     168    uint32_t off, offEnd;
     169    uint32_t i;
     170    int rc;
     171    *ppModLX = NULL;
     172
     173    /*
     174     * Read the signature and file header.
     175     */
     176    rc = kLdrRdrRead(pRdr, &Hdr, sizeof(Hdr), offNewHdr > 0 ? offNewHdr : 0);
     177    if (rc)
     178        return rc;
     179    if (Hdr.e32_magic[0] != E32MAGIC1 || Hdr.e32_magic[0] != E32MAGIC2)
     180        return KLDR_ERR_UNKNOWN_FORMAT;
     181
     182    /* We're not interested in anything but x86 images. */
     183    if (    Hdr.e32_level != E32LEVEL
     184        ||  Hdr.e32_border != E32LEBO
     185        ||  Hdr.e32_worder != E32LEWO
     186        ||  Hdr.e32_cpu < E32CPU286
     187        ||  Hdr.e32_cpu > E32CPU486
     188        ||  Hdr.e32_pagesize != OBJPAGELEN
     189        )
     190        return KLDR_ERR_LX_BAD_HEADER;
     191
     192    /* Some rough sanity checks. */
     193    offEnd = kLdrRdrSize(pRdr) >= (off_t)~(uint32_t)16 ? ~(uint32_t)16 : (uint32_t)kLdrRdrSize(pRdr);
     194    if (    Hdr.e32_itermap > offEnd
     195        ||  Hdr.e32_datapage > offEnd
     196        ||  Hdr.e32_nrestab > offEnd
     197        ||  Hdr.e32_nrestab + Hdr.e32_cbnrestab > offEnd
     198        ||  Hdr.e32_ldrsize > offEnd - offNewHdr - sizeof(Hdr)
     199        ||  Hdr.e32_fixupsize > offEnd - offNewHdr - sizeof(Hdr)
     200        ||  Hdr.e32_fixupsize + Hdr.e32_ldrsize > offEnd - offNewHdr - sizeof(Hdr))
     201        return KLDR_ERR_LX_BAD_HEADER;
     202
     203    /* Verify the loader section. */
     204    offEnd = Hdr.e32_objtab + Hdr.e32_ldrsize;
     205    if (Hdr.e32_objtab < sizeof(Hdr))
     206        return KLDR_ERR_LX_BAD_LOADER_SECTION;
     207    off = Hdr.e32_objtab + sizeof(struct o32_obj) * Hdr.e32_objcnt;
     208    if (off > offEnd)
     209        return KLDR_ERR_LX_BAD_LOADER_SECTION;
     210    if (    Hdr.e32_objmap
     211        &&  (Hdr.e32_objmap < off || Hdr.e32_objmap > offEnd))
     212        return KLDR_ERR_LX_BAD_LOADER_SECTION;
     213    if (    Hdr.e32_rsrccnt
     214        && (   Hdr.e32_rsrctab < off
     215            || Hdr.e32_rsrctab > offEnd
     216            || Hdr.e32_rsrctab + sizeof(struct rsrc32) * Hdr.e32_rsrccnt > offEnd))
     217        return KLDR_ERR_LX_BAD_LOADER_SECTION;
     218    if (    Hdr.e32_restab
     219        &&  (Hdr.e32_restab < off || Hdr.e32_restab > offEnd - 2))
     220        return KLDR_ERR_LX_BAD_LOADER_SECTION;
     221    if (    Hdr.e32_enttab
     222        &&  (Hdr.e32_enttab < off || Hdr.e32_enttab > offEnd - 2))
     223        return KLDR_ERR_LX_BAD_LOADER_SECTION;
     224    if (    Hdr.e32_dircnt
     225        && (Hdr.e32_dirtab < off || Hdr.e32_dirtab > offEnd))
     226        return KLDR_ERR_LX_BAD_LOADER_SECTION;
     227
     228    /* Verify the fixup section. */
     229    off = offEnd;
     230    offEnd = off + Hdr.e32_fixupsize;
     231    if (    Hdr.e32_fpagetab
     232        &&  (Hdr.e32_fpagetab < off || Hdr.e32_fpagetab > offEnd))
     233        return KLDR_ERR_LX_BAD_FIXUP_SECTION;
     234    if (    Hdr.e32_frectab
     235        &&  (Hdr.e32_frectab < off || Hdr.e32_frectab > offEnd))
     236        return KLDR_ERR_LX_BAD_FIXUP_SECTION;
     237    if (    Hdr.e32_impmod
     238        &&  (Hdr.e32_impmod < off || Hdr.e32_impmod > offEnd || Hdr.e32_impmod + Hdr.e32_impmodcnt > offEnd))
     239        return KLDR_ERR_LX_BAD_FIXUP_SECTION;
     240    if (    Hdr.e32_impproc
     241        &&  (Hdr.e32_impproc < off || Hdr.e32_impproc > offEnd))
     242        return KLDR_ERR_LX_BAD_FIXUP_SECTION;
     243
     244    /*
     245     * Calc the instance size, allocate and initialize it.
     246     */
     247    cchFilename = kLdrHlpStrLen(kLdrRdrName(pRdr));
     248    cb = KLDR_ALIGN_Z(sizeof(KLDRMODLX), 8)
     249       + KLDR_ALIGN_Z(KLDR_OFFSETOF(KLDRMOD, aSegments[Hdr.e32_objcnt + 1]), 8)
     250       + KLDR_ALIGN_Z(cchFilename + 1, 8),
     251       + Hdr.e32_ldrsize;
     252    pModLX = (PKLDRMODLX)kldrHlpAlloc(cb);
     253    if (!pModLX)
     254        return KLDR_ERR_NO_MEMORY;
     255    *ppModLX = pModLX;
     256
     257    /* KLDRMOD */
     258    pMod = (PKLDRMOD)((uint8_t *)pModLX + KLDR_ALIGN_Z(sizeof(KLDRMODLX), 8));
     259    pMod->pvData = pModLX;
     260    pMod->pRdr = pRdr;
     261    pMod->pOps = NULL;      /* set upon success. */
     262    pMod->cSegments = Hdr.e32_objcnt;
     263    pMod->cchFilename = cchFilename;
     264    pMod->pszFilename = (char *)KLDR_ALIGN_P(&pMod->aSegments[pMod->cSegments], 8);
     265    kLdrHlpMemCopy((char *)pMod->pszFilename, kLdrRdrName(pRdr), cchFilename + 1);
     266    pMod->pszName = NULL; /* finalized further down */
     267    pMod->cchName = 0;
     268    switch (Hdr.e32_cpu)
     269    {
     270        case E32CPU286:
     271            pMod->enmCpu = KLDRCPU_I80286;
     272            pMod->enmArch = KLDRARCH_X86_16;
     273            break;
     274        case E32CPU386:
     275            pMod->enmCpu = KLDRCPU_I386;
     276            pMod->enmArch = KLDRARCH_X86_32;
     277            break;
     278        case E32CPU486:
     279            pMod->enmCpu = KLDRCPU_I486;
     280            pMod->enmArch = KLDRARCH_X86_32;
     281            break;
     282    }
     283    pMod->enmEndian = KLDRENDIAN_LITTLE;
     284    pMod->enmFmt = KLDRFMT_LX;
     285    switch (Hdr.e32_mflags & E32MODMASK)
     286    {
     287        case E32MODEXE:
     288            pMod->enmType = !(Hdr.e32_mflags & E32NOINTFIX)
     289                ? KLDRTYPE_EXECUTABLE_RELOCATABLE
     290                : KLDRTYPE_EXECUTABLE_FIXED;
     291            break;
     292
     293        case E32MODDLL:
     294        case E32PROTDLL:
     295        case E32MODPROTDLL:
     296            pMod->enmType = !(Hdr.e32_mflags & E32SYSDLL)
     297                ? KLDRTYPE_SHARED_LIBRARY_RELOCATABLE
     298                : KLDRTYPE_SHARED_LIBRARY_FIXED;
     299            break;
     300
     301        case E32MODPDEV:
     302        case E32MODVDEV:
     303            pMod->enmType = KLDRTYPE_SHARED_LIBRARY_RELOCATABLE;
     304            break;
     305    }
     306    pMod->u32Magic = 0;     /* set upon success. */
     307
     308    /* KLDRMODLX */
     309    pModLX->pMod = pMod;
     310    pModLX->pvMapping = 0;
     311    pModLX->cbMapped = Hdr.e32_mpages * Hdr.e32_pagesize;
     312    pModLX->f32Reserved = 0;
     313
     314    pModLX->offHdr = offNewHdr >= 0 ? offNewHdr : 0;
     315    pModLX->Hdr = Hdr;
     316
     317    pModLX->pbLoaderSection = KLDR_ALIGN_P(pMod->pszFilename + pMod->cchFilename + 1, 16);
     318    pModLX->pbLoaderSectionLast = pModLX->pbLoaderSection + pModLX->Hdr.e32_ldrsize;
     319    pModLX->paObjs = NULL;
     320    pModLX->paPageMappings = NULL;
     321    pModLX->paRsrcs = NULL;
     322    pModLX->pbResNameTab = NULL;
     323    pModLX->pbEntryTab = NULL;
     324
     325    pModLX->pbNonResNameTab = NULL;
     326    pModLX->pbNonResNameTabLast = NULL;
     327
     328    pModLX->pbFixupSection = NULL;
     329    pModLX->pbFixupSectionLast = NULL;
     330    pModLX->paoffPageFixups = NULL;
     331    pModLX->pbFixupRecs = NULL;
     332    pModLX->pbImportMods = NULL;
     333    pModLX->pbImportProcs = NULL;
     334
     335    /*
     336     * Read the loader data.
     337     */
     338    rc = kLdrRdrRead(pRdr, (void *)pModLX->pbLoaderSection, pModLX->Hdr.e32_ldrsize, pModLX->Hdr.e32_objtab + pModLX->offHdr);
     339    if (rc)
     340        return rc;
     341    if (pModLX->Hdr.e32_objcnt)
     342        pModLX->paObjs = (const struct o32_obj *)pModLX->pbLoaderSection;
     343    if (pModLX->Hdr.e32_objmap)
     344        pModLX->paPageMappings = (const struct o32_map *)(pModLX->pbLoaderSection + pModLX->Hdr.e32_objmap - pModLX->Hdr.e32_objtab);
     345    if (pModLX->Hdr.e32_rsrccnt)
     346        pModLX->paRsrcs = (const struct rsrc32 *)(pModLX->pbLoaderSection + pModLX->Hdr.e32_rsrctab - pModLX->Hdr.e32_objtab);
     347    if (pModLX->Hdr.e32_restab)
     348        pModLX->pbResNameTab = pModLX->pbLoaderSection + pModLX->Hdr.e32_restab - pModLX->Hdr.e32_objtab;
     349    if (pModLX->Hdr.e32_enttab)
     350        pModLX->pbEntryTab = pModLX->pbLoaderSection + pModLX->Hdr.e32_enttab - pModLX->Hdr.e32_objtab;
     351
     352    /*
     353     * Get the soname from the resident name table.
     354     */
     355    /** @todo */
     356
     357    /*
     358     * Quick validation of the object table.
     359     */
     360    cb = 0;
     361    for (i = 0; i < pMod->cSegments; i++)
     362    {
     363        if (pModLX->paObjs[i].o32_base & (OBJPAGELEN - 1))
     364            return KLDR_ERR_LX_BAD_OBJECT_TABLE;
     365        if (pModLX->paObjs[i].o32_base + pModLX->paObjs[i].o32_size <= pModLX->paObjs[i].o32_base)
     366            return KLDR_ERR_LX_BAD_OBJECT_TABLE;
     367        if (pModLX->paObjs[i].o32_mapsize > pModLX->paObjs[i].o32_size / OBJPAGELEN)
     368            return KLDR_ERR_LX_BAD_OBJECT_TABLE;
     369        if (    pModLX->paObjs[i].o32_mapsize
     370            &&  (   (uint8_t *)&pModLX->paPageMappings[pModLX->paObjs[i].o32_pagemap] > pModLX->pbLoaderSectionLast
     371                 || (uint8_t *)&pModLX->paPageMappings[pModLX->paObjs[i].o32_pagemap + pModLX->paObjs[i].o32_mapsize]
     372                     > pModLX->pbLoaderSectionLast))
     373            return KLDR_ERR_LX_BAD_OBJECT_TABLE;
     374        if (i > 0)
     375        {
     376            if (pModLX->paObjs[i].o32_base <= pModLX->paObjs[i - 1].o32_base)
     377                return KLDR_ERR_LX_BAD_OBJECT_TABLE;
     378            if (pModLX->paObjs[i].o32_base < pModLX->paObjs[i - 1].o32_base + pModLX->paObjs[i - 1].o32_mapsize)
     379                return KLDR_ERR_LX_BAD_OBJECT_TABLE;
     380        }
     381    }
     382    pModLX->cbMapped = pMod->cSegments
     383                     ? pModLX->paObjs[pMod->cSegments - 1].o32_base + pModLX->paObjs[pMod->cSegments - 1].o32_size
     384                       - pModLX->paObjs[pMod->cSegments - 1].o32_size
     385                     : 0;
     386
     387    /*
     388     * Setup the KLDRMOD segment array.
     389     */
     390    for (i = 0; i < pMod->cSegments; i++)
     391    {
     392        /* unused */
     393        pMod->aSegments[i].pvUser = NULL;
     394        pMod->aSegments[i].MapAddress = 0;
     395        pMod->aSegments[i].pchName = NULL;
     396        pMod->aSegments[i].cchName = 0;
     397        pMod->aSegments[i].offFile = -1;
     398        pMod->aSegments[i].cbFile = 0;
     399
     400        /* size and addresses */
     401        pMod->aSegments[i].Alignment   = OBJPAGELEN;
     402        pMod->aSegments[i].cb          = pModLX->paObjs[i].o32_size;
     403        pMod->aSegments[i].LinkAddress = pModLX->paObjs[i].o32_base;
     404        pMod->aSegments[i].RVA         = pModLX->paObjs[i].o32_base - pModLX->paObjs[0].o32_base;
     405        pMod->aSegments[i].cbMapped    = KLDR_ALIGN_Z(pModLX->paObjs[i].o32_size, 16);
     406        if (i + 1 < pMod->cSegments)
     407            pMod->aSegments[i].cbMapped = pModLX->paObjs[i + 1].o32_base - pModLX->paObjs[i].o32_base;
     408
     409        /* protection */
     410        switch (  pModLX->paObjs[i].o32_flags
     411                & (OBJSHARED | OBJREAD | OBJWRITE | OBJEXEC))
     412        {
     413            case 0:
     414            case OBJSHARED:
     415                pMod->aSegments[i].enmProt = KLDRPROT_NOACCESS;
     416                break;
     417            case OBJREAD:
     418            case OBJREAD | OBJSHARED:
     419                pMod->aSegments[i].enmProt = KLDRPROT_READONLY;
     420                break;
     421            case OBJWRITE:
     422            case OBJWRITE | OBJREAD:
     423                pMod->aSegments[i].enmProt = KLDRPROT_WRITECOPY;
     424                break;
     425            case OBJWRITE | OBJSHARED:
     426            case OBJWRITE | OBJSHARED | OBJREAD:
     427                pMod->aSegments[i].enmProt = KLDRPROT_READWRITE;
     428                break;
     429            case OBJEXEC:
     430            case OBJEXEC | OBJSHARED:
     431                pMod->aSegments[i].enmProt = KLDRPROT_EXECUTE;
     432                break;
     433            case OBJEXEC | OBJREAD:
     434            case OBJEXEC | OBJREAD | OBJSHARED:
     435                pMod->aSegments[i].enmProt = KLDRPROT_EXECUTE_READ;
     436                break;
     437            case OBJEXEC | OBJWRITE:
     438            case OBJEXEC | OBJWRITE | OBJREAD:
     439                pMod->aSegments[i].enmProt = KLDRPROT_EXECUTE_WRITECOPY;
     440                break;
     441            case OBJEXEC | OBJWRITE | OBJSHARED:
     442            case OBJEXEC | OBJWRITE | OBJSHARED | OBJREAD:
     443                pMod->aSegments[i].enmProt = KLDRPROT_EXECUTE_READWRITE;
     444                break;
     445        }
     446        if ((pModLX->paObjs[i].o32_flags & (OBJREAD | OBJWRITE | OBJEXEC | OBJRSRC)) == OBJRSRC)
     447            pMod->aSegments[i].enmProt = KLDRPROT_READONLY;
     448        //pMod->aSegments[i].f16bit = !(pModLX->paObjs[i].o32_flags & OBJBIGDEF)
     449        //pMod->aSegments[i].fIOPL = !(pModLX->paObjs[i].o32_flags & OBJIOPL)
     450        //pMod->aSegments[i].fConforming = !(pModLX->paObjs[i].o32_flags & OBJCONFORM)
     451    }
     452
     453    /*
     454     * We're done.
     455     */
     456    *ppModLX = pModLX;
     457    return 0;
     458}
     459
     460
     461/** @copydoc KLDRMODOPS::pfnDestroy */
     462static int kldrModLXDestroy(PKLDRMOD pMod)
     463{
     464    PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData;
     465    int rc = 0;
     466    KLDRMODLX_ASSERT(pModLX->pvMapping);
     467
     468    if (pMod->pRdr)
     469    {
     470        rc = kLdrRdrClose(pMod->pRdr);
     471        pMod->pRdr = NULL;
     472    }
     473    if (pModLX->pbNonResNameTab)
     474    {
     475        kldrHlpFree(pModLX->pbNonResNameTab);
     476        pModLX->pbNonResNameTab = NULL;
     477    }
     478    if (pModLX->pbFixupSection)
     479    {
     480        kldrHlpFree(pModLX->pbFixupSection);
     481        pModLX->pbFixupSection = NULL;
     482    }
     483    if (pMod->pszName)
     484    {
     485        kldrHlpFree((void *)pMod->pszName);
     486        pMod->pszName = NULL;
     487    }
     488    pMod->u32Magic = 0;
     489    pMod->pOps = NULL;
     490    kldrHlpFree(pModLX);
     491    return rc;
     492}
     493
     494
     495/**
     496 * Resolved base address aliases.
     497 *
     498 * @param   pModLX          The interpreter module instance
     499 * @param   pBaseAddress    The base address, IN & OUT.
     500 */
     501static void kldrModLXResolveBaseAddress(PKLDRMODLX pModLX, PKLDRADDR pBaseAddress)
     502{
     503    if (*pBaseAddress == KLDRMOD_BASEADDRESS_MAP)
     504        *pBaseAddress = pModLX->pMod->aSegments[0].MapAddress;
     505    else if (*pBaseAddress == KLDRMOD_BASEADDRESS_LINK)
     506        *pBaseAddress = pModLX->pMod->aSegments[0].LinkAddress;
     507}
     508
     509
     510/** @copydoc kLdrModQuerySymbol */
     511static int kldrModLXQuerySymbol(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, uint32_t iSymbol,
     512                                const char *pszSymbol, PFNKLDRMODGETIMPORT pfnGetForwarder, void *pvUser,
     513                                PKLDRADDR puValue, uint32_t *pfKind)
     514{
     515    PKLDRMODLX                      pModLX = (PKLDRMODLX)pMod->pvData;
     516    //int                             rc;
     517
     518    kldrModLXResolveBaseAddress(pModLX, &BaseAddress);
     519
     520    return -1;
     521}
     522
     523
     524/** @copydoc kLdrModEnumSymbols */
     525static int kldrModLXEnumSymbols(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress,
     526                                uint32_t fFlags, PFNKLDRMODENUMSYMS pfnCallback, void *pvUser)
     527{
     528    PKLDRMODLX                      pModLX = (PKLDRMODLX)pMod->pvData;
     529//    int                             rc;
     530
     531    kldrModLXResolveBaseAddress(pModLX, &BaseAddress);
     532
     533    return -1;
     534}
     535
     536
     537/** @copydoc kLdrModGetImport */
     538static int kldrModLXGetImport(PKLDRMOD pMod, const void *pvBits, uint32_t iImport, char *pszName, size_t cchName)
     539{
     540    PKLDRMODLX      pModLX = (PKLDRMODLX)pMod->pvData;
     541    const uint8_t * pb = NULL;
     542    int             rc;
     543
     544    /** @todo */
     545
     546    if (*pb < cchName)
     547    {
     548        kLdrHlpMemCopy(pszName, pb + 1, *pb);
     549        pszName[*pb] = '\0';
     550        rc = 0;
     551    }
     552    else
     553    {
     554        kLdrHlpMemCopy(pszName, pb + 1, cchName);
     555        if (cchName)
     556            pszName[cchName - 1] = '\0';
     557        rc = KLDR_ERR_BUFFER_OVERFLOW;
     558    }
     559
     560    return rc;
     561}
     562
     563
     564/** @copydoc kLdrModNumberOfImports */
     565static int32_t kldrModLXNumberOfImports(PKLDRMOD pMod, const void *pvBits)
     566{
     567    PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData;
     568    return pModLX->Hdr.e32_impmodcnt;
     569}
     570
     571
     572/** @copydoc kLdrModGetStackInfo */
     573static int kldrModLXGetStackInfo(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, PKLDRSTACKINFO pStackInfo)
     574{
     575    PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData;
     576    const uint32_t i = pModLX->Hdr.e32_stackobj;
     577
     578    if (    i
     579        &&  i <= pMod->cSegments
     580        &&  pModLX->Hdr.e32_esp <= pMod->aSegments[i - 1].LinkAddress + pMod->aSegments[i - 1].cb
     581        &&  pModLX->Hdr.e32_stacksize
     582        &&  pModLX->Hdr.e32_esp - pModLX->Hdr.e32_stacksize >= pMod->aSegments[i - 1].LinkAddress)
     583    {
     584
     585        kldrModLXResolveBaseAddress(pModLX, &BaseAddress);
     586        pStackInfo->LinkAddress = pModLX->Hdr.e32_esp - pModLX->Hdr.e32_stacksize;
     587        pStackInfo->Address = BaseAddress
     588                            + pMod->aSegments[i - 1].RVA
     589                            + pModLX->Hdr.e32_esp - pModLX->Hdr.e32_stacksize - pMod->aSegments[i - 1].LinkAddress;
     590    }
     591    else
     592    {
     593        pStackInfo->Address = NIL_KLDRADDR;
     594        pStackInfo->LinkAddress = NIL_KLDRADDR;
     595    }
     596    pStackInfo->cbStack = pModLX->Hdr.e32_stacksize;
     597    pStackInfo->cbStackThread = 0;
     598
     599    return 0;
     600}
     601
     602
     603/** @copydoc kLdrModQueryMainEntrypoint */
     604static int kldrModLXQueryMainEntrypoint(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, PKLDRADDR pMainEPAddress)
     605{
     606    PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData;
     607
     608    /*
     609     * Convert the address from the header.
     610     */
     611    kldrModLXResolveBaseAddress(pModLX, &BaseAddress);
     612    *pMainEPAddress = pModLX->Hdr.e32_startobj
     613                   && pModLX->Hdr.e32_startobj <= pMod->cSegments
     614                   && pModLX->Hdr.e32_eip < pMod->aSegments[pModLX->Hdr.e32_startobj - 1].cb
     615        ? BaseAddress + pMod->aSegments[pModLX->Hdr.e32_startobj - 1].RVA + pModLX->Hdr.e32_eip
     616        : NIL_KLDRADDR;
     617    return 0;
     618}
     619
     620
     621/** @copydoc kLdrModEnumDbgInfo */
     622static int kldrModLXEnumDbgInfo(PKLDRMOD pMod, const void *pvBits, PFNKLDRENUMDBG pfnCallback, void *pvUser)
     623{
     624    //PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData;
     625
     626    /*
     627     * Quit immediately if no debug info.
     628     */
     629    if (kldrModLXHasDbgInfo(pMod, pvBits))
     630        return 0;
     631#if 0
     632    /*
     633     * Read the debug info and look for familiar magics and structures.
     634     */
     635    /** @todo */
     636#endif
     637
     638    return 0;
     639}
     640
     641
     642/** @copydoc kLdrModHasDbgInfo */
     643static int kldrModLXHasDbgInfo(PKLDRMOD pMod, const void *pvBits)
     644{
     645    PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData;
     646
     647    /*
     648     * Don't curretnly bother with linkers which doesn't advertise it in the header.
     649     */
     650    if (    !pModLX->Hdr.e32_debuginfo
     651        ||  !pModLX->Hdr.e32_debuglen)
     652        return KLDR_ERR_NO_DEBUG_INFO;
     653    return 0;
     654}
     655
     656
     657/** @copydoc kLdrModMap */
     658static int kldrModLXMap(PKLDRMOD pMod)
     659{
     660    PKLDRMODLX  pModLX = (PKLDRMODLX)pMod->pvData;
     661    unsigned    fFixed;
     662    void       *pvBase;
     663    int         rc;
     664
     665    /*
     666     * Already mapped?
     667     */
     668    if (pModLX->pvMapping)
     669        return KLDR_ERR_ALREADY_MAPPED;
     670
     671    /*
     672     * Allocate memory for it.
     673     */
     674    /* fixed image? */
     675    fFixed = pMod->enmType == KLDRTYPE_EXECUTABLE_FIXED
     676          || pMod->enmType == KLDRTYPE_SHARED_LIBRARY_FIXED;
     677    if (!fFixed)
     678        pvBase = NULL;
     679    else
     680    {
     681        pvBase = (void *)(uintptr_t)pMod->aSegments[0].LinkAddress;
     682        if ((uintptr_t)pvBase != pMod->aSegments[0].LinkAddress)
     683            return KLDR_ERR_ADDRESS_OVERFLOW;
     684    }
     685    rc = kldrHlpPageAlloc(&pvBase, pModLX->cbMapped, KLDRPROT_EXECUTE_READWRITE, fFixed);
     686    if (rc)
     687        return rc;
     688
     689    /*
     690     * Load the bits, apply page protection, and update the segment table.
     691     */
     692    rc = kldrModLXDoLoadBits(pModLX, pvBase);
     693    if (!rc)
     694        rc = kldrModLXDoProtect(pModLX, pvBase, 0 /* protect */);
     695    if (!rc)
     696    {
     697        uint32_t i;
     698        for (i = 0; i < pMod->cSegments; i++)
     699        {
     700            if (pMod->aSegments[i].RVA != NIL_KLDRADDR)
     701                pMod->aSegments[i].MapAddress = (uintptr_t)pvBase + (uintptr_t)pMod->aSegments[i].RVA;
     702        }
     703        pModLX->pvMapping = pvBase;
     704    }
     705    else
     706        kldrHlpPageFree(pvBase, pModLX->cbMapped);
     707    return rc;
     708}
     709
     710
     711/**
     712 * Loads the LX pages into the specified memory mapping.
     713 *
     714 * @returns 0 on success.
     715 * @returns non-zero kLdr or OS status code on failure.
     716 *
     717 * @param   pModLX  The LX module interpreter instance.
     718 * @param   pvBits  Where to load the bits.
     719 */
     720static int kldrModLXDoLoadBits(PKLDRMODLX pModLX, void *pvBits)
     721{
     722    //E32NOLOAD
     723
     724    return -1;
     725}
     726
     727
     728/**
     729 * Unprotects or protects the specified image mapping.
     730 *
     731 * @returns 0 on success.
     732 * @returns non-zero kLdr or OS status code on failure.
     733 *
     734 * @param   pModLX  The LX module interpreter instance.
     735 * @param   pvBits  The mapping to protect.
     736 * @param   UnprotectOrProtect  If 1 unprotect (i.e. make all writable), otherwise
     737 *          protect according to the object table.
     738 */
     739static int kldrModLXDoProtect(PKLDRMODLX pMod, void *pvBits, unsigned fUnprotectOrProtect)
     740{
     741    return -1;
     742}
     743
     744
     745/** @copydoc kLdrModUnmap */
     746static int kldrModLXUnmap(PKLDRMOD pMod)
     747{
     748    PKLDRMODLX  pModLX = (PKLDRMODLX)pMod->pvData;
     749    uint32_t    i;
     750    int         rc;
     751
     752    /*
     753     * Mapped?
     754     */
     755    if (!pModLX->pvMapping)
     756        return KLDR_ERR_NOT_MAPPED;
     757
     758    /*
     759     * Free the mapping and update the segments.
     760     */
     761    rc = kldrHlpPageFree((void *)pModLX->pvMapping, pModLX->cbMapped);
     762    KLDRMODLX_ASSERT(!rc);
     763    pModLX->pvMapping = NULL;
     764
     765    for (i = 0; i < pMod->cSegments; i++)
     766        pMod->aSegments[i].MapAddress = 0;
     767
     768    return rc;
     769}
     770
     771
     772/** @copydoc kLdrModAllocTLS */
     773static int kldrModLXAllocTLS(PKLDRMOD pMod)
     774{
     775    PKLDRMODLX  pModLX = (PKLDRMODLX)pMod->pvData;
     776
     777    /* just do the error checking. */
     778    if (!pModLX->pvMapping)
     779        return KLDR_ERR_NOT_MAPPED;
     780    return 0;
     781}
     782
     783
     784/** @copydoc kLdrModFreeTLS */
     785static void kldrModLXFreeTLS(PKLDRMOD pMod)
     786{
     787}
     788
     789
     790/** @copydoc kLdrModReload */
     791static int kldrModLXReload(PKLDRMOD pMod)
     792{
     793    PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData;
     794
     795    /*
     796     * Mapped?
     797     */
     798    if (!pModLX->pvMapping)
     799        return KLDR_ERR_NOT_MAPPED;
     800
     801    /* the file provider does it all */
     802    return kLdrRdrRefresh(pMod->pRdr, (void *)pModLX->pvMapping, pMod->cSegments, pMod->aSegments);
     803}
     804
     805
     806/** @copydoc kLdrModFixupMapping */
     807static int kldrModLXFixupMapping(PKLDRMOD pMod, PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser)
     808{
     809    PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData;
     810    int rc, rc2;
     811
     812    /*
     813     * Mapped?
     814     */
     815    if (!pModLX->pvMapping)
     816        return KLDR_ERR_NOT_MAPPED;
     817
     818    /*
     819     * Before doing anything we'll have to make all pages writable.
     820     */
     821    rc = kLdrRdrProtect(pMod->pRdr, (void *)pModLX->pvMapping, pMod->cSegments, pMod->aSegments, 1 /* unprotect */);
     822    if (rc)
     823        return rc;
     824
     825    /*
     826     * Apply fixups and resolve imports.
     827     */
     828    rc = kldrModLXRelocateBits(pMod, (void *)pModLX->pvMapping, (uintptr_t)pModLX->pvMapping,
     829                               pMod->aSegments[0].LinkAddress, pfnGetImport, pvUser);
     830
     831    /*
     832     * Restore protection.
     833     */
     834    rc2 = kLdrRdrProtect(pMod->pRdr, (void *)pModLX->pvMapping, pMod->cSegments, pMod->aSegments, 0 /* protect */);
     835    if (!rc && rc2)
     836        rc = rc2;
     837    return rc;
     838}
     839
     840
     841/** @copydoc kLdrModCallInit */
     842static int kldrModLXCallInit(PKLDRMOD pMod, uintptr_t uHandle)
     843{
     844    PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData;
     845    int rc;
     846
     847    /*
     848     * Mapped?
     849     */
     850    if (!pModLX->pvMapping)
     851        return KLDR_ERR_NOT_MAPPED;
     852
     853    /*
     854     * Do TLS callbacks first and then call the init/term function if it's a DLL.
     855     */
     856    if ((pModLX->Hdr.e32_mflags & E32MODMASK) == E32MODDLL)
     857        rc = kldrModLXDoCallDLL(pModLX, 0 /* attach */, uHandle);
     858    else
     859        rc = 0;
     860    return rc;
     861}
     862
     863
     864/**
     865 * Call the DLL entrypoint.
     866 *
     867 * @returns 0 on success.
     868 * @returns KLDR_ERR_MODULE_INIT_FAILED  or KLDR_ERR_THREAD_ATTACH_FAILED on failure.
     869 * @param   pModLX          The LX module interpreter instance.
     870 * @param   uOp             The operation (DLL_*).
     871 * @param   uHandle         The module handle to present.
     872 */
     873static int kldrModLXDoCallDLL(PKLDRMODLX pModLX, unsigned uOp, uintptr_t uHandle)
     874{
     875    int rc;
     876
     877    /*
     878     * If no entrypoint there isn't anything to be done.
     879     */
     880    if (    !pModLX->Hdr.e32_startobj
     881        ||  pModLX->Hdr.e32_startobj > pModLX->Hdr.e32_objcnt)
     882        return 0;
     883
     884    /*
     885     * Invoke the entrypoint and convert the boolean result to a kLdr status code.
     886     */
     887    rc = kldrModLXDoCall((uintptr_t)pModLX->pvMapping
     888                         + (uintptr_t)pModLX->pMod->aSegments[pModLX->Hdr.e32_startobj - 1].RVA
     889                         + pModLX->Hdr.e32_eip,
     890                         uHandle, uOp, NULL);
     891    if (rc)
     892        rc = 0;
     893    else if (uOp == 0 /* attach */)
     894        rc = KLDR_ERR_MODULE_INIT_FAILED;
     895    else /* detach: ignore failures */
     896        rc = 0;
     897    return rc;
     898}
     899
     900
     901/**
     902 * Do a 3 parameter callback.
     903 *
     904 * @returns 32-bit callback return.
     905 * @param   uEntrypoint     The address of the function to be called.
     906 * @param   uHandle         The first argument, the module handle.
     907 * @param   uOp             The second argumnet, the reason we're calling.
     908 * @param   pvReserved      The third argument, reserved argument. (figure this one out)
     909 */
     910static int32_t kldrModLXDoCall(uintptr_t uEntrypoint, uintptr_t uHandle, uint32_t uOp, void *pvReserved)
     911{
     912#if defined(__X86__) || defined(__i386__) || defined(_M_IX86)
     913    int32_t rc;
     914/** @todo try/except */
     915
     916    /*
     917     * Paranoia.
     918     */
     919# ifdef __GNUC__
     920    __asm__ __volatile__(
     921        "pushl  %2\n\t"
     922        "pushl  %1\n\t"
     923        "pushl  %0\n\t"
     924        "lea   12(%%esp), %2\n\t"
     925        "call  *%3\n\t"
     926        "movl   %2, %%esp\n\t"
     927        : "=a" (rc)
     928        : "d" (uOp),
     929          "S" (0),
     930          "c" (uEntrypoint),
     931          "0" (uHandle));
     932# elif defined(_MSC_VER)
     933    __asm {
     934        mov     eax, [uHandle]
     935        mov     edx, [uOp]
     936        mov     ecx, 0
     937        mov     ebx, [uEntrypoint]
     938        push    edi
     939        mov     edi, esp
     940        push    ecx
     941        push    edx
     942        push    eax
     943        call    ebx
     944        mov     esp, edi
     945        pop     edi
     946        mov     [rc], eax
     947    }
     948# else
     949#  error "port me!"
     950# endif
     951    return rc;
     952
     953#else
     954    return KLDR_ERR_ARCH_CPU_NOT_COMPATIBLE;
     955#endif
     956}
     957
     958
     959/** @copydoc kLdrModCallTerm */
     960static int kldrModLXCallTerm(PKLDRMOD pMod, uintptr_t uHandle)
     961{
     962    PKLDRMODLX  pModLX = (PKLDRMODLX)pMod->pvData;
     963
     964    /*
     965     * Mapped?
     966     */
     967    if (!pModLX->pvMapping)
     968        return KLDR_ERR_NOT_MAPPED;
     969
     970    /*
     971     * Do the call.
     972     */
     973    if ((pModLX->Hdr.e32_mflags & E32MODMASK) == E32MODDLL)
     974        kldrModLXDoCallDLL(pModLX, 1 /* detach */, uHandle);
     975
     976    return 0;
     977}
     978
     979
     980/** @copydoc kLdrModCallThread */
     981static int kldrModLXCallThread(PKLDRMOD pMod, uintptr_t uHandle, unsigned fAttachingOrDetaching)
     982{
     983    return 0;
     984}
     985
     986
     987/** @copydoc kLdrModSize */
     988static KLDRADDR kldrModLXSize(PKLDRMOD pMod)
     989{
     990    PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData;
     991    return pModLX->cbMapped;
     992}
     993
     994
     995/** @copydoc kLdrModGetBits */
     996static int kldrModLXGetBits(PKLDRMOD pMod, void *pvBits, KLDRADDR BaseAddress, PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser)
     997{
     998    PKLDRMODLX  pModLX = (PKLDRMODLX)pMod->pvData;
     999    int         rc;
     1000
     1001    /*
     1002     * Load the image bits.
     1003     */
     1004    rc = kldrModLXDoLoadBits(pModLX, pvBits);
     1005    if (rc)
     1006        return rc;
     1007
     1008    /*
     1009     * Perform relocations.
     1010     */
     1011    return kldrModLXRelocateBits(pMod, pvBits, BaseAddress, pMod->aSegments[0].LinkAddress, pfnGetImport, pvUser);
     1012
     1013}
     1014
     1015
     1016/** @copydoc kLdrModRelocateBits */
     1017static int kldrModLXRelocateBits(PKLDRMOD pMod, void *pvBits, KLDRADDR NewBaseAddress, KLDRADDR OldBaseAddress,
     1018                                 PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser)
     1019{
     1020    //PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData;
     1021    //int rc;
     1022
     1023    /** @todo Implement this. */
     1024
     1025    return -1;
     1026}
     1027
     1028
     1029/**
     1030 * The LX module interpreter method table.
     1031 */
     1032KLDRMODOPS g_kLdrModLXOps =
     1033{
     1034    "LX",
     1035    NULL,
     1036    kldrModLXCreate,
     1037    kldrModLXDestroy,
     1038    kldrModLXQuerySymbol,
     1039    kldrModLXEnumSymbols,
     1040    kldrModLXGetImport,
     1041    kldrModLXNumberOfImports,
     1042    NULL /* can execute one is optional */,
     1043    kldrModLXGetStackInfo,
     1044    kldrModLXQueryMainEntrypoint,
     1045    kldrModLXEnumDbgInfo,
     1046    kldrModLXHasDbgInfo,
     1047    kldrModLXMap,
     1048    kldrModLXUnmap,
     1049    kldrModLXAllocTLS,
     1050    kldrModLXFreeTLS,
     1051    kldrModLXReload,
     1052    kldrModLXFixupMapping,
     1053    kldrModLXCallInit,
     1054    kldrModLXCallTerm,
     1055    kldrModLXCallThread,
     1056    kldrModLXSize,
     1057    kldrModLXGetBits,
     1058    kldrModLXRelocateBits,
     1059    42 /* the end */
     1060};
     1061
Note: See TracChangeset for help on using the changeset viewer.