Changeset 10397 for trunk/src


Ignore:
Timestamp:
Jan 15, 2004, 11:39:15 AM (22 years ago)
Author:
sandervl
Message:

Loader updates

Location:
trunk/src/kernel32
Files:
20 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/kernel32/windllbase.cpp

    r10054 r10397  
    1 /* $Id: windllbase.cpp,v 1.33 2003-04-30 11:04:07 sandervl Exp $ */
     1/* $Id: windllbase.cpp,v 1.34 2004-01-15 10:39:06 sandervl Exp $ */
    22
    33/*
     
    55 *
    66 * Copyright 1998-2000 Sander van Leeuwen (sandervl@xs4all.nl)
     7 * Copyright 2003 Innotek Systemberatung GmbH (sandervl@innotek.de)
    78 *
    89 * Unloading of a dll always happens in order of dependency (taking nr of
     
    438439#ifdef DEBUG
    439440    time2 = GetTickCount();
    440     dprintf(("attachProcess to dll %s DONE in %x msec", szModule, time2-time1));
     441    dprintf(("attachProcess to dll %s DONE in %x msec rc %d", szModule, time2-time1, rc));
    441442#endif
    442443
     
    883884//******************************************************************************
    884885//******************************************************************************
     886int Win32DllBase::enumDlls(HMODULE *lphModule, int countMax)
     887{
     888    int     count = 0;
     889    HMODULE hModule;
     890
     891    dlllistmutex.enter();
     892
     893    Win32DllBase *mod = Win32DllBase::head;
     894    while(mod != NULL) {
     895        dbgCheckObj(mod);
     896
     897        hModule = mod->getInstanceHandle();
     898        if ( count < countMax )
     899            lphModule[count] = hModule;
     900        count++;
     901
     902        mod = mod->next;
     903    }
     904    dlllistmutex.leave();
     905    return count;
     906}
     907//******************************************************************************
     908//******************************************************************************
    885909Win32DllBase *Win32DllBase::head = NULL;
    886910Queue         Win32DllBase::loadLibDlls;
  • trunk/src/kernel32/windllbase.h

    r8923 r10397  
    1 /* $Id: windllbase.h,v 1.10 2002-07-26 10:48:40 sandervl Exp $ */
     1/* $Id: windllbase.h,v 1.11 2004-01-15 10:39:06 sandervl Exp $ */
    22
    33/*
     
    8686    BOOL      isDynamicLib()   { return nrDynamicLibRef != 0; };
    8787
     88    WIN32DLLENTRY getEntryPoint()  { return dllEntryPoint; };
     89
    8890    void      setUnloadOrder(Win32ImageBase *parent);
    8991
     
    114116static  Win32DllBase *findModuleByAddr(ULONG address);
    115117static  Win32DllBase *findModuleByOS2Handle(HINSTANCE hinstance);
     118
     119static  int           enumDlls(HMODULE *lphModule, int countMax);
    116120
    117121#ifdef DEBUG
  • trunk/src/kernel32/windlllx.cpp

    r10304 r10397  
    1 /* $Id: windlllx.cpp,v 1.28 2003-10-28 10:42:40 sandervl Exp $ */
     1/* $Id: windlllx.cpp,v 1.29 2004-01-15 10:39:07 sandervl Exp $ */
    22
    33/*
     
    55 *
    66 * Copyright 1999-2000 Sander van Leeuwen (sandervl@xs4all.nl)
     7 * Copyright 2003 Innotek Systemberatung GmbH (sandervl@innotek.de)
    78 *
    89 * TODO: Unloading of dlls probably needs to be fixed due to OS/2 bug
     
    4546*******************************************************************************/
    4647char *lpszCustomDllName      = NULL;
    47 char *lpszCustomExportPrefix = NULL;
    48 ULONG dwOrdinalBase          = 0;
     48PIMAGE_FILE_HEADER lpCustomDllPEHdr = NULL;
    4949
    5050/**
     
    5757//******************************************************************************
    5858//******************************************************************************
    59 void WIN32API SetCustomBuildName(char *lpszName, PIMAGE_FILE_HEADER  pfh)
    60 
     59void WIN32API SetCustomBuildName(char *lpszName, PIMAGE_FILE_HEADER pfh)
    6160{
    6261    lpszCustomDllName      = lpszName;
     62    lpCustomDllPEHdr       = pfh;
    6363}
    6464//******************************************************************************
     
    101101       }
    102102   }
     103   else {
     104       //make sure this dll hasn't already been loaded
     105       if(Win32DllBase::findModule(lpszCustomDllName) != NULL) {
     106           dprintf(("ERROR: RegisterLxDll: module %s already loaded!!", lpszCustomDllName));
     107           DebugInt3();
     108           return 0;
     109       }
     110   }
    103111   windll = new Win32LxDll(hInstance, EntryPoint, pResData, MajorImageVersion,
    104112                           MinorImageVersion, Subsystem);
     
    109117   //clear name override in case dll init loads another dll
    110118   lpszCustomDllName = NULL;
     119   lpCustomDllPEHdr  = NULL;
    111120
    112121   if(!fPeLoader) {
  • trunk/src/kernel32/windlllx.h

    r9411 r10397  
    1 /* $Id: windlllx.h,v 1.8 2002-11-18 13:53:54 sandervl Exp $ */
     1/* $Id: windlllx.h,v 1.9 2004-01-15 10:39:07 sandervl Exp $ */
    22
    33/*
     
    4747};
    4848
    49 extern char *lpszCustomDllName, *lpszCustomExportPrefix;
    50 extern DWORD dwOrdinalBase;
     49extern char *lpszCustomDllName;
     50extern PIMAGE_FILE_HEADER lpCustomDllPEHdr;
    5151
    5252#endif //__WINDLLLX_H__
  • trunk/src/kernel32/windllpe2lx.cpp

    r9963 r10397  
    1 /* $Id: windllpe2lx.cpp,v 1.14 2003-03-31 11:54:28 sandervl Exp $ */
     1/* $Id: windllpe2lx.cpp,v 1.15 2004-01-15 10:39:08 sandervl Exp $ */
    22
    33/*
  • trunk/src/kernel32/windllpe2lx.h

    r9963 r10397  
    1 /* $Id: windllpe2lx.h,v 1.3 2003-03-31 11:54:28 sandervl Exp $ */
     1/* $Id: windllpe2lx.h,v 1.4 2004-01-15 10:39:08 sandervl Exp $ */
    22
    33/*
  • trunk/src/kernel32/windllpeldr.cpp

    r9975 r10397  
    1 /* $Id: windllpeldr.cpp,v 1.12 2003-04-02 12:58:31 sandervl Exp $ */
     1/* $Id: windllpeldr.cpp,v 1.13 2004-01-15 10:39:08 sandervl Exp $ */
    22
    33/*
     
    55 *
    66 * Copyright 1999 Sander van Leeuwen (sandervl@xs4all.nl)
     7 * Copyright 2003 Innotek Systemberatung GmbH (sandervl@innotek.de)
    78 *
    89 *
     
    8384  dllEntryPoint = (WIN32DLLENTRY)entryPoint;
    8485
    85   if(!(fh.Characteristics & IMAGE_FILE_DLL)) {
     86  if(!(Characteristics & IMAGE_FILE_DLL)) {
    8687    //executable loaded as dll; don't call entrypoint
    8788    dprintf(("WARNING: Exe %s loaded as dll; entrypoint not called", szFileName));
  • trunk/src/kernel32/windllpeldr.h

    r9975 r10397  
    1 /* $Id: windllpeldr.h,v 1.4 2003-04-02 12:58:31 sandervl Exp $ */
     1/* $Id: windllpeldr.h,v 1.5 2004-01-15 10:39:09 sandervl Exp $ */
    22
    33/*
  • trunk/src/kernel32/winexedummy.cpp

    r10386 r10397  
    1 /* $Id: winexedummy.cpp,v 1.5 2004-01-12 17:27:28 sandervl Exp $ */
     1/* $Id: winexedummy.cpp,v 1.6 2004-01-15 10:39:09 sandervl Exp $ */
    22
    33/*
  • trunk/src/kernel32/winexelx.cpp

    r9800 r10397  
    1 /* $Id: winexelx.cpp,v 1.12 2003-02-13 15:30:53 sandervl Exp $ */
     1/* $Id: winexelx.cpp,v 1.13 2004-01-15 10:39:10 sandervl Exp $ */
    22
    33/*
  • trunk/src/kernel32/winexepe2lx.cpp

    r9540 r10397  
    1 /* $Id: winexepe2lx.cpp,v 1.13 2002-12-20 12:40:43 sandervl Exp $ */
     1/* $Id: winexepe2lx.cpp,v 1.14 2004-01-15 10:39:10 sandervl Exp $ */
    22
    33/*
  • trunk/src/kernel32/winexepeldr.cpp

    r9780 r10397  
    1 /* $Id: winexepeldr.cpp,v 1.23 2003-02-10 16:05:39 sandervl Exp $ */
     1/* $Id: winexepeldr.cpp,v 1.24 2004-01-15 10:39:10 sandervl Exp $ */
    22
    33/*
     
    184184    //Note: MUST use 128kb as a minimum. Or else the workarounds for out of
    185185    //      stack space in 16 bits code (thread entrypoint) might fail.
    186     return (oh.SizeOfStackReserve > 128*1024) ? oh.SizeOfStackReserve : 128*1024;
     186    return (poh->SizeOfStackReserve > 128*1024) ? poh->SizeOfStackReserve : 128*1024;
    187187}
    188188//******************************************************************************
  • trunk/src/kernel32/winimagebase.cpp

    r9617 r10397  
    1 /* $Id: winimagebase.cpp,v 1.36 2003-01-05 12:31:25 sandervl Exp $ */
     1/* $Id: winimagebase.cpp,v 1.37 2004-01-15 10:39:11 sandervl Exp $ */
    22
    33/*
     
    66 * Copyright 1998-1999 Sander van Leeuwen (sandervl@xs4all.nl)
    77 * Copyright 1998-2000 knut st. osmundsen (knut.stange.osmundsen@mynd.no)
     8 * Copyright 2003 Innotek Systemberatung GmbH (sandervl@innotek.de)
    89 *
    910 * Project Odin Software License can be found in LICENSE.TXT
     
    4849    errorState(NO_ERROR), entryPoint(0), fullpath(NULL),
    4950    tlsAddress(0), tlsIndexAddr(0), tlsInitSize(0), tlsTotalSize(0),
    50     tlsCallBackAddr(0), tlsIndex(-1), pResRootDir(NULL),
    51     ulRVAResourceSection(0), fIsPEImage(FALSE)
     51    tlsCallBackAddr(0), tlsIndex(-1), pResRootDir(NULL), poh(NULL),
     52    ulRVAResourceSection(0), fIsPEImage(FALSE), pExportDir(NULL)
    5253{
    5354  char *name;
     
    153154}
    154155//******************************************************************************
     156//
     157//  Win32ImageBase::findApi: find function in export table and change if necessary
     158//
     159//  Parameters:
     160//      char *name              - function name (NULL for ordinal search)
     161//      int ordinal             - function ordinal (only used if name == NULL)
     162//      ULONG pfnNewProc        - new function address (ignored if 0)
     163//
     164//  Returns:
     165//      0                       - not found
     166//      <>0                     - function address
     167//
     168//******************************************************************************
     169ULONG Win32ImageBase::findApi(char *pszName, ULONG ulOrdinal, ULONG pfnNewProc)
     170{
     171    PIMAGE_EXPORT_DIRECTORY ped = pExportDir;
     172
     173    /*
     174     * Get ped if it's NULL.
     175     */
     176    if (!ped)
     177    {
     178        if (!poh->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress)
     179            return 0;
     180        ped = (PIMAGE_EXPORT_DIRECTORY)getPointerFromRVA(poh->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
     181        pExportDir = ped;
     182    }
     183
     184    int     iExpOrdinal = 0;            /* index into address table. */
     185    if (pszName)
     186    {
     187        /*
     188         * Find Named Export: Do binary search on the name table.
     189         */
     190        const char**paRVANames = (const char **)getPointerFromRVA(ped->AddressOfNames);
     191        PUSHORT     paOrdinals = (PUSHORT)getPointerFromRVA(ped->AddressOfNameOrdinals);
     192        int         iStart = 1;
     193        int         iEnd = ped->NumberOfNames;
     194
     195        for (;;)
     196        {
     197            /* end of search? */
     198            if (iStart > iEnd)
     199            {
     200            #ifdef DEBUG
     201                /* do a linear search just to verify the correctness of the above algorithm */
     202                for (int i = 0; i < ped->NumberOfNames; i++)
     203                    if (!strcmp(paRVANames[i - 1] + (unsigned)hinstance, pszName))
     204                    {
     205                        dprintf(("bug in binary export search!!!\n"));
     206                        DebugInt3();
     207                    }
     208            #endif
     209                return 0;
     210            }
     211
     212            int i  = (iEnd - iStart) / 2 + iStart;
     213            const char *pszExpName  = (const char *)getPointerFromRVA(paRVANames[i - 1]);
     214            int         diff        = strcmp(pszExpName, pszName);
     215            if (diff > 0)       /* pszExpName > pszName: search chunck before i */
     216                iEnd = i - 1;
     217            else if (diff)      /* pszExpName < pszName: search chunk after i */
     218                iStart = i + 1;
     219            else                /* pszExpName == pszName */
     220            {
     221                iExpOrdinal = paOrdinals[i - 1];
     222                break;
     223            }
     224        } /* binary search thru name table */
     225    }
     226    else
     227    {
     228        /*
     229         * Find ordinal export: Simple table lookup.
     230         */
     231        if (    ulOrdinal >= ped->Base + max(ped->NumberOfNames, ped->NumberOfFunctions)
     232            ||  ulOrdinal < ped->Base)
     233            return NULL;
     234        iExpOrdinal = ulOrdinal - ped->Base;
     235    }
     236
     237    /*
     238     * Found export (iExpOrdinal).
     239     */
     240    PULONG      paAddress = (PULONG)getPointerFromRVA(ped->AddressOfFunctions);
     241    unsigned    uRVAExport  = paAddress[iExpOrdinal];
     242    unsigned    uRet;
     243
     244    /* Install override for the export (if requested) */
     245    if (pfnNewProc && uRet)
     246        paAddress[iExpOrdinal] = getRVAFromPointer((void*)pfnNewProc, TRUE);
     247
     248    if (    uRVAExport > poh->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress
     249        &&  uRVAExport < poh->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress
     250            + poh->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size)
     251        /* Resolve forwarder. */
     252        uRet = findForwarder(poh->ImageBase + uRVAExport, pszName, iExpOrdinal);
     253    else
     254        /* Get plain export address */
     255        uRet = (ULONG)getPointerFromRVA(uRVAExport, TRUE);
     256
     257    return uRet;
     258}
     259//******************************************************************************
     260//******************************************************************************
     261ULONG Win32ImageBase::findForwarder(ULONG virtaddr, char *apiname, ULONG ordinal)
     262{
     263    char         *forward;
     264    char         *forwarddll, *forwardapi;
     265    Win32DllBase *WinDll;
     266    DWORD         exportaddr;
     267    int           forwardord;
     268    int           iForwardDllLength;
     269    int           iForwardApiLength;
     270
     271    forward = (char *)(hinstance + (virtaddr - poh->ImageBase));
     272    iForwardDllLength = strlen(forward);
     273
     274    if(iForwardDllLength == 0)
     275        return 0;
     276
     277    forwarddll = (char*)alloca(iForwardDllLength);
     278    if(forwarddll == NULL) {
     279        DebugInt3();
     280        return 0;
     281    }
     282    memcpy(forwarddll, forward, iForwardDllLength + 1);
     283
     284    forwardapi = strchr(forwarddll, '.');
     285    if(forwardapi == NULL) {
     286        return 0;
     287    }
     288    *forwardapi++ = 0;
     289    iForwardApiLength = strlen(forwardapi);
     290    if(iForwardApiLength == 0) {
     291        return FALSE;
     292    }
     293    WinDll = Win32DllBase::findModule(forwarddll);
     294    if(WinDll == NULL) {
     295        return 0;
     296    }
     297    //check if name or ordinal forwarder
     298    forwardord = 0;
     299    if(*forwardapi >= '0' && *forwardapi <= '9') {
     300        forwardord = atoi(forwardapi);
     301    }
     302    if(forwardord != 0 || (iForwardApiLength == 1 && *forwardapi == '0')) {
     303         exportaddr = WinDll->getApi(forwardord);
     304    }
     305    else exportaddr = WinDll->getApi(forwardapi);
     306
     307    return exportaddr;
     308}
     309//******************************************************************************
    155310//******************************************************************************
    156311ULONG Win32ImageBase::setApi(char *name, ULONG pfnNewProc)
    157312{
    158     return -1; //only implemented for PE modules
     313    return findApi(name, 0, pfnNewProc);
    159314}
    160315//******************************************************************************
     
    162317ULONG Win32ImageBase::setApi(int ordinal, ULONG pfnNewProc)
    163318{
    164     return -1; //only implemented for PE modules
     319    return findApi(NULL, ordinal, pfnNewProc);
     320}
     321//******************************************************************************
     322//******************************************************************************
     323ULONG Win32ImageBase::getApi(char *name)
     324{
     325    return findApi(name, 0);
     326}
     327//******************************************************************************
     328//******************************************************************************
     329ULONG Win32ImageBase::getApi(int ordinal)
     330{
     331    return findApi(NULL, ordinal);
    165332}
    166333//******************************************************************************
     
    227394//the Characteristics member of the file header structure)
    228395//******************************************************************************
    229 ULONG Win32ImageBase::isPEImage(char *szFileName, DWORD *Characteristics, 
     396ULONG Win32ImageBase::isPEImage(char *szFileName, DWORD *Characteristics,
    230397                                DWORD *subsystem, DWORD *fNEExe)
    231398{
     
    243410 int    nSections, i;
    244411
    245   if(fNEExe) 
     412  if(fNEExe)
    246413      *fNEExe = FALSE;
    247414
     
    306473  }
    307474
    308   if(GetPEFileHeader (win32file, &fh) == FALSE) 
     475  if(GetPEFileHeader (win32file, &fh) == FALSE)
    309476  {
    310477        if(*(WORD *)PE_HEADER(win32file) == IMAGE_OS2_SIGNATURE) {
    311             if(fNEExe) 
     478            if(fNEExe)
    312479                *fNEExe = TRUE;
    313480        }
     
    334501        *subsystem = oh.Subsystem;
    335502  }
    336  
     503
    337504  free(win32file);
    338505  DosClose(win32handle);
     
    414581    return stricmp(pszModName, szModule) == 0;
    415582}
     583
     584/** Converts a RVA to an pointer into the loaded image.
     585 * @returns Pointer corresponding to the RVA.
     586 * @param   ulRVA       RVA to make a pointer.
     587 * @param   fOverride   Flags if the RVA might be to an overridden address (export).
     588 */
     589void *Win32ImageBase::getPointerFromRVA(ULONG ulRVA, BOOL fOverride/* = FALSE*/)
     590{
     591    return (PVOID)((char*)hinstance + ulRVA);
     592}
     593
     594/** Converts a pointer to an RVA for the loaded image.
     595 * @returns Pointer corresponding to the RVA.
     596 * @param   ulRVA       RVA to make a pointer.
     597 * @param   fOverride   Flags if the pointer might be to an overridden address (export).
     598 */
     599ULONG Win32ImageBase::getRVAFromPointer(void *pv, BOOL fOverride/* = FALSE*/)
     600{
     601    return (ULONG)pv - (ULONG)hinstance;
     602}
     603
  • trunk/src/kernel32/winimagebase.h

    r9617 r10397  
    1 /* $Id: winimagebase.h,v 1.23 2003-01-05 12:31:25 sandervl Exp $ */
     1/* $Id: winimagebase.h,v 1.24 2004-01-15 10:39:11 sandervl Exp $ */
    22
    33/*
     
    110110virtual BOOL  insideModuleCode(ULONG address);
    111111
    112 virtual ULONG getApi(char *name)  = 0;
    113 virtual ULONG getApi(int ordinal) = 0;
     112virtual ULONG getApi(char *name);
     113virtual ULONG getApi(int ordinal);
    114114
    115115virtual ULONG setApi(char *name, ULONG pfnNewProc);
     
    132132    void tlsAlloc();        //Allocate TLS index for this module
    133133    void tlsDelete();       //Destroy TLS index for this module
     134
     135    ULONG findApi(char *pszName, ULONG ulOrdinal, ULONG pfnNewProc = NULL);
     136    ULONG findForwarder(ULONG virtaddr, char *apiname, ULONG ordinal);
     137    virtual void *getPointerFromRVA(ULONG ulRVA, BOOL fOverride = FALSE);
     138    void *        getPointerFromRVA(const void *pvRVA)  { return getPointerFromRVA((ULONG)pvRVA); }
     139    virtual ULONG getRVAFromPointer(void *pv, BOOL fOverride = FALSE);
    134140
    135141    ULONG                   errorState,
     
    161167    PIMAGE_RESOURCE_DIRECTORY   pResRootDir;
    162168
     169    PIMAGE_EXPORT_DIRECTORY     pExportDir;
     170    PIMAGE_OPTIONAL_HEADER      poh;
     171
    163172    //substracted from RVA data offsets
    164173    ULONG                   ulRVAResourceSection;
  • trunk/src/kernel32/winimagelx.cpp

    r9971 r10397  
    1 /* $Id: winimagelx.cpp,v 1.20 2003-04-02 11:03:33 sandervl Exp $ */
     1/* $Id: winimagelx.cpp,v 1.21 2004-01-15 10:39:11 sandervl Exp $ */
    22
    33/*
     
    55 *
    66 * Copyright 1999-2000 Sander van Leeuwen (sandervl@xs4all.nl)
     7 * Copyright 2003 Innotek Systemberatung GmbH (sandervl@innotek.de)
     8 *
     9 * header adjustment & fixup_rva_ptrs borrowed from Wine (Rewind)
     10 * Copyright 2000 Alexandre Julliard
    711 *
    812 * TODO: headers not complete
    9  * 
     13 *
    1014 * Project Odin Software License can be found in LICENSE.TXT
    1115 *
     
    6266
    6367//******************************************************************************
     68/* adjust an array of pointers to make them into RVAs */
     69//******************************************************************************
     70static inline void fixup_rva_ptrs( void *array, void *base, int count )
     71{
     72    void **ptr = (void **)array;
     73    while (count--)
     74    {
     75        if (*ptr) *ptr = (void *)((char *)*ptr - (char *)base);
     76        ptr++;
     77    }
     78}
     79//******************************************************************************
    6480//******************************************************************************
    6581Win32LxImage::Win32LxImage(HINSTANCE hInstance, PVOID pResData)
    66                : Win32ImageBase(hInstance), header(0)
     82               : Win32ImageBase(hInstance), header(0), pCustomPEHeader(0)
    6783{
    6884    APIRET rc;
     
    7187    szFileName[0] = 0;
    7288
    73     this->lpszExportPrefix = NULL;
    74     if(lpszCustomDllName) {
    75        name = lpszCustomDllName;
    76        this->dwOrdinalBase    = ::dwOrdinalBase;
    77      
    78        if(lpszCustomExportPrefix) {
    79            this->lpszExportPrefix = strdup(::lpszCustomExportPrefix);
    80        }
     89    if (lpszCustomDllName) {
     90       name            = lpszCustomDllName;
     91       pCustomPEHeader = lpCustomDllPEHdr;
     92
     93       hinstance = (DWORD)pCustomPEHeader;
     94       if (pCustomPEHeader) {
     95           //Calculate address of optional header
     96           poh = (PIMAGE_OPTIONAL_HEADER)OPTHEADEROFF(pCustomPEHeader);
     97
     98           //Update the header data to reflect the new load address
     99           poh->ImageBase = hinstance;
     100
     101           PIMAGE_EXPORT_DIRECTORY pExpDir;
     102           pExpDir = (PIMAGE_EXPORT_DIRECTORY)((char*)hinstance
     103                + poh->DataDirectory[IMAGE_FILE_EXPORT_DIRECTORY].VirtualAddress);
     104           fixup_rva_ptrs((char*)hinstance + (unsigned)pExpDir->AddressOfFunctions,
     105                          (LPVOID)hinstance,
     106                          pExpDir->NumberOfFunctions );
     107        }
    81108    }
    82109    else {
    83110       name = OSLibGetDllName(hinstance);
    84        this->dwOrdinalBase    = 0;
    85111    }
    86112
     
    102128Win32LxImage::~Win32LxImage()
    103129{
    104     if(lpszExportPrefix) free(lpszExportPrefix);
    105 
    106130    if(header) {
    107131        DosFreeMem(header);
     
    115139    ULONG       apiaddr;
    116140
    117     if(lpszExportPrefix)
    118     {//if this dll exports by name with a prefix, then concatenate the prefix
    119      //with the export name to get the OS/2 export name
    120         char *lpszNewName = (char *)alloca(strlen(name) + strlen(lpszExportPrefix)+1);
    121         if(lpszNewName == NULL) {
    122             DebugInt3();
    123             return 0;
    124         }
    125         strcpy(lpszNewName, lpszExportPrefix);
    126         strcat(lpszNewName, name);
    127         rc = DosQueryProcAddr(hinstanceOS2, 0, lpszNewName, (PFN *)&apiaddr);
    128         if(rc == NO_ERROR) {
    129             return(apiaddr);
    130         }
    131         //else try with the normal name
    132     }
     141    if(pCustomPEHeader) return Win32ImageBase::getApi(name);
     142
    133143    rc = DosQueryProcAddr(hinstanceOS2, 0, name, (PFN *)&apiaddr);
    134144    if(rc)
     
    146156    ULONG       apiaddr;
    147157
    148     rc = DosQueryProcAddr(hinstanceOS2, dwOrdinalBase+ordinal, NULL, (PFN *)&apiaddr);
     158    if(pCustomPEHeader) return Win32ImageBase::getApi(ordinal);
     159
     160    rc = DosQueryProcAddr(hinstanceOS2, ordinal, NULL, (PFN *)&apiaddr);
    149161    if(rc) {
    150162        dprintf(("Win32LxImage::getApi %x %d -> rc = %d", hinstanceOS2, ordinal, rc));
     
    155167//******************************************************************************
    156168//******************************************************************************
     169ULONG Win32LxImage::setApi(char *name, ULONG pfnNewProc)
     170{
     171    if(pCustomPEHeader) return Win32ImageBase::setApi(name, pfnNewProc);
     172
     173    return -1;
     174}
     175//******************************************************************************
     176//******************************************************************************
     177ULONG Win32LxImage::setApi(int ordinal, ULONG pfnNewProc)
     178{
     179    if(pCustomPEHeader) return Win32ImageBase::setApi(ordinal, pfnNewProc);
     180
     181    return -1;
     182}
     183//******************************************************************************
     184//******************************************************************************
    157185LPVOID Win32LxImage::buildHeader(DWORD MajorImageVersion, DWORD MinorImageVersion,
    158                                  DWORD Subsystem) 
     186                                 DWORD Subsystem)
    159187{
    160188    APIRET rc;
    161189    IMAGE_DOS_HEADER *pdosheader;
    162     PIMAGE_OPTIONAL_HEADER poh;
    163     PIMAGE_FILE_HEADER     pfh;
     190    PIMAGE_OPTIONAL_HEADER  poh;
     191    PIMAGE_FILE_HEADER      pfh;
     192    PIMAGE_SECTION_HEADER   psh;
     193    PIMAGE_EXPORT_DIRECTORY ped;
     194
     195    if(pCustomPEHeader)
     196    {
     197        return (LPVOID)pCustomPEHeader;
     198    }
     199
    164200    DWORD *ntsig;
    165201
     
    180216    pfh->NumberOfSymbols      = 0;
    181217    pfh->SizeOfOptionalHeader = sizeof(IMAGE_OPTIONAL_HEADER);
    182     pfh->Characteristics      = IMAGE_FILE_DLL | IMAGE_FILE_32BIT_MACHINE | 
    183                                 IMAGE_FILE_DEBUG_STRIPPED | IMAGE_FILE_EXECUTABLE_IMAGE | 
     218    pfh->Characteristics      = IMAGE_FILE_DLL | IMAGE_FILE_32BIT_MACHINE |
     219                                IMAGE_FILE_DEBUG_STRIPPED | IMAGE_FILE_EXECUTABLE_IMAGE |
    184220                                IMAGE_FILE_RELOCS_STRIPPED;
    185221    poh    = (PIMAGE_OPTIONAL_HEADER)(pfh+1);
     
    214250    poh->LoaderFlags                 = 0;
    215251    poh->NumberOfRvaAndSizes         = 0;
    216 //  poh->DataDirectory[0]
    217252
    218253    return header;
  • trunk/src/kernel32/winimagelx.h

    r9411 r10397  
    1 /* $Id: winimagelx.h,v 1.7 2002-11-18 13:53:55 sandervl Exp $ */
     1/* $Id: winimagelx.h,v 1.8 2004-01-15 10:39:12 sandervl Exp $ */
    22
    33/*
     
    2424virtual ULONG     getApi(int ordinal);
    2525
     26virtual ULONG     setApi(char *name, ULONG pfnNewProc);
     27virtual ULONG     setApi(int ordinal, ULONG pfnNewProc);
     28
    2629        LPVOID    buildHeader(DWORD MajorImageVersion, DWORD MinorImageVersion,
    2730                              DWORD Subsystem);
     
    2932         * @returns OS/2 module handle. */
    3033        HINSTANCE   getHMOD() const { return hinstanceOS2; }
     34
    3135protected:
    3236  LPVOID    header;
    3337  HINSTANCE hinstanceOS2;
    34   DWORD     dwOrdinalBase;
    35   LPSTR     lpszExportPrefix;
     38
     39  //custom build PE header
     40  LPVOID    pCustomPEHeader;
     41
    3642private:
    3743};
  • trunk/src/kernel32/winimagepe2lx.cpp

    r9537 r10397  
    1 /* $Id: winimagepe2lx.cpp,v 1.21 2002-12-20 11:39:42 sandervl Exp $ */
     1/* $Id: winimagepe2lx.cpp,v 1.22 2004-01-15 10:39:12 sandervl Exp $ */
    22
    33/*
     
    3535#include <misc.h>
    3636#include "winimagebase.h"
     37#include "windllbase.h"
     38#include "winexebase.h"
    3739#include "winimagepe2lx.h"
     40#include "winimagepeldr.h"
     41#include "windllpeldr.h"
     42#include "winimagelx.h"
     43#include "windlllx.h"
    3844#include "Win32k.h"
    3945
     
    259265    hinstance = (HINSTANCE)paSections[0].ulAddress;
    260266
     267    /* Set poh & pExportDir (base class stuff) */
     268    poh = &pNtHdrs->OptionalHeader;
     269    pExportDir = (PIMAGE_EXPORT_DIRECTORY)getPointerFromRVA(pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
     270
    261271    /* Locate and set the entrypoint. */
    262272    setEntryPoint((ULONG)getPointerFromRVA(pNtHdrs->OptionalHeader.AddressOfEntryPoint));
     
    272282
    273283    /* Locate the resource directory (if any) */
    274     if (pNtHdrs->OptionalHeader.NumberOfRvaAndSizes > IMAGE_DIRECTORY_ENTRY_RESOURCE
    275         && pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress > 0UL)
    276     {
    277         ulRVAResourceSection = pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress;
    278         pResRootDir = (PIMAGE_RESOURCE_DIRECTORY)getPointerFromRVA(ulRVAResourceSection);
    279         /* _temporary_ fix:
    280          *  We'll have to make the resource section writable.
    281          *  And we'll have to make the pages before it readable.
    282          */
    283         LONG iSection = getSectionIndexFromRVA(ulRVAResourceSection);
    284         if (iSection >= 0)
    285         {
    286             rc = DosSetMem((PVOID)paSections[iSection].ulAddress, paSections[iSection].cbVirtual, PAG_WRITE | PAG_READ);
    287 
    288             ULONG ulAddr = paSections[iSection].ulAddress - 0x10000; //64KB
    289             while (ulAddr < paSections[iSection].ulAddress)
    290             {
    291                 ULONG fl = ~0UL;
    292                 ULONG cb = ~0UL;
    293                 rc = DosQueryMem((PVOID)ulAddr, &cb, &fl);
    294                 if (rc == NO_ERROR)
    295                 {
    296                     if (fl & PAG_GUARD)
    297                         rc = -1;
    298                     else if (fl & PAG_COMMIT)
    299                         fl &= ~(PAG_COMMIT);
    300                     else
    301                         fl |= PAG_COMMIT;
    302                     cb = (cb + 0xfffUL) & ~0xfffUL;
    303                 }
    304                 else
    305                 {
    306                     fl = PAG_COMMIT;
    307                     cb = 0x1000;
    308                 }
    309                 fl &= PAG_READ | PAG_COMMIT | PAG_WRITE | PAG_GUARD;
    310                 fl |= PAG_READ;
    311                 if (cb > paSections[iSection].ulAddress - ulAddr)
    312                     cb = paSections[iSection].ulAddress - ulAddr;
    313                 if (rc == NO_ERROR)
    314                     rc = DosSetMem((PVOID)ulAddr, cb, fl);
    315 
    316                 ulAddr += cb;
    317             }
    318         }
    319     }
    320 
    321     /* TLS - Thread Local Storage */
    322     if (pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress != 0UL
    323         && pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].Size != 0UL)
    324     {
    325         PIMAGE_TLS_DIRECTORY pTLSDir;
    326         LONG                 iSection;
    327         iSection = getSectionIndexFromRVA(pNtHdrs->OptionalHeader.
    328                                           DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].
    329                                           VirtualAddress);
    330         pTLSDir = (PIMAGE_TLS_DIRECTORY)getPointerFromRVA(pNtHdrs->OptionalHeader.
    331                                                           DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].
    332                                                           VirtualAddress);
    333 
    334         if (pTLSDir != NULL && iSection != -1)
    335         {
    336             PVOID pv;
    337 
    338             /*
    339              * According to the docs StartAddressOfRawData and EndAddressOfRawData is
    340              * real pointers with a baserelocs.
    341              *
    342              * The docs says nothing about the two AddressOf pointers. So, we'll assume that
    343              * these also are real pointers. But, we'll try compensate if they should not have
    344              * base realocations.
    345              */
    346             if (validateRealPointer((PVOID)pTLSDir->StartAddressOfRawData)
    347                 &&
    348                 validateRealPointer((PVOID)pTLSDir->EndAddressOfRawData)
    349                 )
    350             {
    351                 setTLSAddress((PVOID)pTLSDir->StartAddressOfRawData);
    352                 setTLSInitSize(pTLSDir->EndAddressOfRawData - pTLSDir->StartAddressOfRawData);
    353                 setTLSTotalSize(pTLSDir->EndAddressOfRawData - pTLSDir->StartAddressOfRawData + pTLSDir->SizeOfZeroFill);
    354 
    355                 if (pTLSDir->AddressOfIndex)
    356                 {
    357                     if (validateRealPointer(pTLSDir->AddressOfIndex))
    358                         /* assume baserelocations for thepointer; use it without any change. */
    359                         setTLSIndexAddr((LPDWORD)(void*)pTLSDir->AddressOfIndex);
    360                     else
    361                     {   /* assume no baserelocs for these pointers? Complain and debugint3 */
    362                         eprintf(("Win32Pe2LxImage::init: TLS - AddressOfIndex(%#8x) is not a pointer with basereloc.\n",
    363                                  pTLSDir->AddressOfIndex));
    364                         pv = getPointerFromPointer(pTLSDir->AddressOfIndex);
    365                         if (pv == NULL)
    366                         {
    367                             eprintf(("Win32Pe2LxImage::init: invalid RVA to TLS AddressOfIndex - %#8x.\n",
    368                                      pTLSDir->AddressOfIndex));
    369                             return LDRERROR_INVALID_HEADER;
    370                         }
    371                         setTLSIndexAddr((LPDWORD)pv);
    372                     }
    373                 }
    374 
    375                 if (pTLSDir->AddressOfCallBacks)
    376                 {
    377                     if (validateRealPointer(pTLSDir->AddressOfCallBacks))
    378                         /* assume baserelocations for thepointer; use it without any change. */
    379                         setTLSCallBackAddr(pTLSDir->AddressOfCallBacks);
    380                     else
    381                     {   /* assume no baserelocs for these pointers? Complain and debugint3 */
    382                         eprintf(("Win32Pe2LxImage::init: Warning: TLS - AddressOfCallBacks(%#8x) is not a pointer with basereloc.\n",
    383                                  pTLSDir->AddressOfCallBacks));
    384                         pv = getPointerFromPointer(pTLSDir->AddressOfCallBacks);
    385                         if (pv == NULL)
    386                         {
    387                             eprintf(("Win32Pe2LxImage::init: invalid pointer to TLS AddressOfCallBacks - %#8x.\n",
    388                                      pTLSDir->AddressOfIndex));
    389                             return LDRERROR_INVALID_HEADER;
    390                         }
    391                         setTLSCallBackAddr((PIMAGE_TLS_CALLBACK*)pv);
    392                     }
    393                 }
    394             }
    395         }
    396         else
    397         {
    398             eprintf(("Win32Pe2LxImage::init: invalid RVA to TLS Dir - %#8x. (getPointerFromRVA failed)\n",
    399                      pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress));
    400             return LDRERROR_INVALID_HEADER;
    401         }
    402     }
     284    rc = doResources();
     285    if (rc)
     286        return rc;
     287
     288    /*
     289     * TLS - Thread Local Storage
     290     */
     291    rc = doTLS();
     292    if (rc)
     293        return rc;
     294
     295
     296    /*
     297     * Process imports.
     298     */
     299    rc = doImports();
     300    if (rc)
     301        return rc;
     302
    403303    return LDRERROR_SUCCESS;
    404304}
    405 
    406305
    407306
     
    688587
    689588/**
     589 * Process resource section.
     590 */
     591ULONG Win32Pe2LxImage::doResources()
     592{
     593    ULONG   rc;
     594
     595    if (pNtHdrs->OptionalHeader.NumberOfRvaAndSizes > IMAGE_DIRECTORY_ENTRY_RESOURCE
     596        && pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress > 0UL)
     597    {
     598        ulRVAResourceSection = pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress;
     599        pResRootDir = (PIMAGE_RESOURCE_DIRECTORY)getPointerFromRVA(ulRVAResourceSection);
     600        /* _temporary_ fix:
     601         *  We'll have to make the resource section writable.
     602         *  And we'll have to make the pages before it readable.
     603         */
     604        LONG iSection = getSectionIndexFromRVA(ulRVAResourceSection);
     605        if (iSection >= 0)
     606        {
     607            rc = DosSetMem((PVOID)paSections[iSection].ulAddress, paSections[iSection].cbVirtual, PAG_WRITE | PAG_READ);
     608
     609            ULONG ulAddr = paSections[iSection].ulAddress - 0x10000; //64KB
     610            while (ulAddr < paSections[iSection].ulAddress)
     611            {
     612                ULONG fl = ~0UL;
     613                ULONG cb = ~0UL;
     614                rc = DosQueryMem((PVOID)ulAddr, &cb, &fl);
     615                if (rc == NO_ERROR)
     616                {
     617                    if (fl & PAG_GUARD)
     618                        rc = -1;
     619                    else if (fl & PAG_COMMIT)
     620                        fl &= ~(PAG_COMMIT);
     621                    else
     622                        fl |= PAG_COMMIT;
     623                    cb = (cb + 0xfffUL) & ~0xfffUL;
     624                }
     625                else
     626                {
     627                    fl = PAG_COMMIT;
     628                    cb = 0x1000;
     629                }
     630                fl &= PAG_READ | PAG_COMMIT | PAG_WRITE | PAG_GUARD;
     631                fl |= PAG_READ;
     632                if (cb > paSections[iSection].ulAddress - ulAddr)
     633                    cb = paSections[iSection].ulAddress - ulAddr;
     634                if (rc == NO_ERROR)
     635                    rc = DosSetMem((PVOID)ulAddr, cb, fl);
     636
     637                ulAddr += cb;
     638            }
     639        }
     640    }
     641
     642    return 0;
     643}
     644
     645
     646/**
     647 * Do TLS related matters.
     648 */
     649ULONG Win32Pe2LxImage::doTLS()
     650{
     651    if (pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress != 0UL
     652        && pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].Size != 0UL)
     653    {
     654        PIMAGE_TLS_DIRECTORY pTLSDir;
     655        LONG                 iSection;
     656        iSection = getSectionIndexFromRVA(pNtHdrs->OptionalHeader.
     657                                          DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].
     658                                          VirtualAddress);
     659        pTLSDir = (PIMAGE_TLS_DIRECTORY)getPointerFromRVA(pNtHdrs->OptionalHeader.
     660                                                          DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].
     661                                                          VirtualAddress);
     662
     663        if (pTLSDir != NULL && iSection != -1)
     664        {
     665            PVOID pv;
     666
     667            /*
     668             * According to the docs StartAddressOfRawData and EndAddressOfRawData is
     669             * real pointers with a baserelocs.
     670             *
     671             * The docs says nothing about the two AddressOf pointers. So, we'll assume that
     672             * these also are real pointers. But, we'll try compensate if they should not have
     673             * base realocations.
     674             */
     675            if (validateRealPointer((PVOID)pTLSDir->StartAddressOfRawData)
     676                &&
     677                validateRealPointer((PVOID)pTLSDir->EndAddressOfRawData)
     678                )
     679            {
     680                setTLSAddress((PVOID)pTLSDir->StartAddressOfRawData);
     681                setTLSInitSize(pTLSDir->EndAddressOfRawData - pTLSDir->StartAddressOfRawData);
     682                setTLSTotalSize(pTLSDir->EndAddressOfRawData - pTLSDir->StartAddressOfRawData + pTLSDir->SizeOfZeroFill);
     683
     684                if (pTLSDir->AddressOfIndex)
     685                {
     686                    if (validateRealPointer(pTLSDir->AddressOfIndex))
     687                        /* assume baserelocations for thepointer; use it without any change. */
     688                        setTLSIndexAddr((LPDWORD)(void*)pTLSDir->AddressOfIndex);
     689                    else
     690                    {   /* assume no baserelocs for these pointers? Complain and debugint3 */
     691                        eprintf(("Win32Pe2LxImage::init: TLS - AddressOfIndex(%#8x) is not a pointer with basereloc.\n",
     692                                 pTLSDir->AddressOfIndex));
     693                        pv = getPointerFromPointer(pTLSDir->AddressOfIndex);
     694                        if (pv == NULL)
     695                        {
     696                            eprintf(("Win32Pe2LxImage::init: invalid RVA to TLS AddressOfIndex - %#8x.\n",
     697                                     pTLSDir->AddressOfIndex));
     698                            return LDRERROR_INVALID_HEADER;
     699                        }
     700                        setTLSIndexAddr((LPDWORD)pv);
     701                    }
     702                }
     703
     704                if (pTLSDir->AddressOfCallBacks)
     705                {
     706                    if (validateRealPointer(pTLSDir->AddressOfCallBacks))
     707                        /* assume baserelocations for thepointer; use it without any change. */
     708                        setTLSCallBackAddr(pTLSDir->AddressOfCallBacks);
     709                    else
     710                    {   /* assume no baserelocs for these pointers? Complain and debugint3 */
     711                        eprintf(("Win32Pe2LxImage::init: Warning: TLS - AddressOfCallBacks(%#8x) is not a pointer with basereloc.\n",
     712                                 pTLSDir->AddressOfCallBacks));
     713                        pv = getPointerFromPointer(pTLSDir->AddressOfCallBacks);
     714                        if (pv == NULL)
     715                        {
     716                            eprintf(("Win32Pe2LxImage::init: invalid pointer to TLS AddressOfCallBacks - %#8x.\n",
     717                                     pTLSDir->AddressOfIndex));
     718                            return LDRERROR_INVALID_HEADER;
     719                        }
     720                        setTLSCallBackAddr((PIMAGE_TLS_CALLBACK*)pv);
     721                    }
     722                }
     723            }
     724        }
     725        else
     726        {
     727            eprintf(("Win32Pe2LxImage::init: invalid RVA to TLS Dir - %#8x. (getPointerFromRVA failed)\n",
     728                     pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress));
     729            return LDRERROR_INVALID_HEADER;
     730        }
     731    }
     732
     733    return 0;
     734}
     735
     736/**
     737 * Processes the import directory of the image.
     738 * @returns LDRERROR_*
     739 * @remark  This could be in base class and shared with the peldr.
     740 */
     741ULONG   Win32Pe2LxImage::doImports()
     742{
     743    ULONG                       rc;
     744    PIMAGE_IMPORT_DESCRIPTOR    pImps;
     745
     746    /*
     747     * Check if there is actually anything to work on.
     748     */
     749    if (   !pNtHdrs->OptionalHeader.DataDirectory[IMAGE_FILE_IMPORT_DIRECTORY].VirtualAddress
     750        || !pNtHdrs->OptionalHeader.DataDirectory[IMAGE_FILE_IMPORT_DIRECTORY].Size)
     751    {
     752        dprintf(("Win32Pe2LxImage::initImports: there are no imports\n"));
     753        return 0;
     754    }
     755
     756    /*
     757     * Walk the IMAGE_IMPORT_DESCRIPTOR table.
     758     */
     759    for (rc = 0, pImps = (PIMAGE_IMPORT_DESCRIPTOR)getPointerFromRVA(pNtHdrs->OptionalHeader.DataDirectory[IMAGE_FILE_IMPORT_DIRECTORY].VirtualAddress);
     760         !rc && pImps->Name != 0 && pImps->FirstThunk != 0;
     761         pImps++)
     762    {
     763        const char *        pszName = (const char*)getPointerFromRVA(pImps->Name);
     764        Win32ImageBase     *pModule;
     765        dprintf(("Win32Pe2LxImage::initImports: DLL %s\n", pszName));
     766
     767        /*
     768         * Try find the table.
     769         */
     770        pModule = importsGetModule(pszName);
     771        if (pModule)
     772        {
     773            PIMAGE_THUNK_DATA   pFirstThunk;    /* update this. */
     774            PIMAGE_THUNK_DATA   pThunk;         /* read from this. */
     775
     776            /*
     777             * Walk the thunks table(s).
     778             */
     779            pFirstThunk = (PIMAGE_THUNK_DATA)getPointerFromRVA((ULONG)pImps->FirstThunk);
     780            pThunk = pImps->u.OriginalFirstThunk == 0 ? pFirstThunk
     781                : (PIMAGE_THUNK_DATA)getPointerFromRVA((ULONG)pImps->FirstThunk);
     782            while (!rc && pThunk->u1.Ordinal != 0)
     783            {
     784                if (pThunk->u1.Ordinal & IMAGE_ORDINAL_FLAG)
     785                    rc = importsByOrdinal(pModule, IMAGE_ORDINAL(pThunk->u1.Ordinal), (void**)&pFirstThunk->u1.Function);
     786                else if (   pThunk->u1.Ordinal > 0
     787                         && pThunk->u1.Ordinal < pNtHdrs->OptionalHeader.SizeOfImage)
     788                    rc = importsByName(pModule, (const char*)getPointerFromRVA((ULONG)pThunk->u1.AddressOfData + 2), (void**)&pFirstThunk->u1.Function);
     789                else
     790                {
     791                    dprintf(("Win32Pe2LxImage::initImports: bad import data thunk!\n"));
     792                    DebugInt3();
     793                    rc = LDRERROR_IMPORTS;
     794                }
     795
     796                pThunk++;
     797                pFirstThunk++;
     798            }
     799        }
     800        else
     801        {
     802            dprintf(("Win32Pe2LxImage::initImports: cannot find module '%s'!!!\n", pszName));
     803            DebugInt3();
     804            rc = LDRERROR_IMPORTS;
     805        }
     806    }
     807
     808    return rc;
     809}
     810
     811
     812/**
     813 * Find a module.
     814 *
     815 * @returns Pointer to module
     816 * @returns NULL on failure.
     817 * @param   pszModName  Pointer to module name.
     818 * @remark  This should be in base class and shared with the peldr.
     819 */
     820Win32ImageBase * Win32Pe2LxImage::importsGetModule(const char *pszModName)
     821{
     822    Win32ImageBase *pMod;
     823    Win32DllBase   *pDll;
     824
     825    /*
     826     * Look if it's already loaded.
     827     */
     828    pDll = Win32DllBase::findModule((char*)pszModName);
     829    if (pDll)
     830    {
     831        dprintf(("Win32Pe2LxImage::importGetModule(%s) already loaded\n", pszModName));
     832        pDll->AddRef();
     833    }
     834    else if (WinExe != NULL && WinExe->matchModName(pszModName))
     835    {
     836        dprintf(("Win32Pe2LxImage::importGetModule(%s) already loaded (exe)\n", pszModName));
     837        pMod = (Win32ImageBase *)WinExe;
     838        pDll = NULL;
     839    }
     840    else
     841    {
     842        /*
     843         * Load it (simplified).
     844         */
     845        pDll = importsLoadModule(pszModName);
     846        if (!pDll)
     847            return NULL;
     848        dprintf(("Win32Pe2LxImage::importGetModule(%s) Loaded module\n", pszModName));
     849    }
     850
     851    /*
     852     * Update dependendcies.
     853     */
     854    if (pDll)
     855    {
     856        /*
     857         * Add the dll we just loaded to dependency list for this image.
     858         */
     859        addDependency(pDll);
     860
     861        /*
     862         * Make sure the dependency list is correct (already done in the ctor
     863         * of Win32DllBase, but for LX dlls the parent is then set to NULL)
     864         * so, change it here again
     865         */
     866        pDll->setUnloadOrder(this);
     867        pMod = pDll;
     868    }
     869
     870    return pMod;
     871}
     872
     873/**
     874 * Loads a module this module is depending on.
     875 * @returns Pointer to loaded module.
     876 * @returns NULL on failure.
     877 * @param   pszModName  Name of the module to be loaded.
     878 * @remark  This should be in base class and shared with the peldr.
     879 */
     880Win32DllBase *Win32Pe2LxImage::importsLoadModule(const char *pszModName)
     881{
     882    Win32DllBase   *pDll;
     883    char            szRenamed[CCHMAXPATH];
     884
     885    /*
     886     * Copy and rename the module name. (i.e. OLE32 -> OLE32OS2)
     887     */
     888    Win32DllBase::renameDll(strcpy(szRenamed, pszModName));
     889
     890    /*
     891     * Find the filename (using the standard search stuff).
     892     */
     893    char            szFullname[CCHMAXPATH];
     894    if (!Win32ImageBase::findDll(szRenamed, szFullname, sizeof(szFullname)))
     895    {
     896        dprintf(("Module %s not found!", szRenamed));
     897        errorState = ERROR_FILE_NOT_FOUND;
     898        return NULL;
     899    }
     900
     901    /*
     902     * Check which type of executable module this is.
     903     */
     904    if (isPEImage(szFullname, NULL, NULL) != ERROR_SUCCESS_W)
     905    {
     906        /*
     907         * LX image: let OS/2 do all the work for us
     908         */
     909        char    szModuleFailure[CCHMAXPATH];
     910        HMODULE hmodLXDll;
     911        APIRET  rc;
     912
     913        rc = DosLoadModule(szModuleFailure, sizeof(szModuleFailure), szFullname, (HMODULE *)&hmodLXDll);
     914        if (rc)
     915        {
     916            dprintf(("DosLoadModule returned %X for %s", rc, szModuleFailure));
     917            errorState = rc;
     918            return NULL;
     919        }
     920
     921        pDll = Win32DllBase::findModuleByOS2Handle((HINSTANCE)hmodLXDll);
     922        if (pDll == NULL)
     923        {
     924            dprintf(("Just loaded the dll, but can't find it anywhere?!!?"));
     925            DebugInt3();
     926            errorState = ERROR_INTERNAL;
     927            return NULL;
     928        }
     929
     930        /*
     931         * For none Pe2Lx'ed LX modules we'll have to do a little work here.
     932         */
     933        if (pDll->isLxDll())
     934        {
     935            Win32LxDll *pLXDll = (Win32LxDll *)pDll;
     936            pLXDll->setDllHandleOS2(hmodLXDll);
     937            if (pLXDll->AddRef() == -1) //-1 -> load failed (attachProcess)
     938            {
     939                dprintf(("Dll %s refused to be loaded; aborting", szFullname));
     940                delete pLXDll;
     941                errorState = ERROR_INTERNAL;
     942                return NULL;
     943            }
     944        }
     945    }
     946    else
     947    {
     948        /*
     949         * PE image: use the peldr.
     950         */
     951        Win32PeLdrDll *pPEDll;
     952
     953        pPEDll = new Win32PeLdrDll(szFullname, this);
     954        if (!pPEDll)
     955        {
     956            dprintf(("pedll: Error allocating memory" ));
     957            errorState = ERROR_INTERNAL;
     958            return NULL;
     959        }
     960        dprintf(("**********************************************************************"));
     961        dprintf(("**********************     Loading Module        *********************"));
     962        dprintf(("**********************************************************************"));
     963        if (pPEDll->init(0) != LDRERROR_SUCCESS)
     964        {
     965            dprintf(("Internal WinDll error ", pPEDll->getError()));
     966            delete pPEDll;
     967            return NULL;
     968        }
     969
     970#ifdef DEBUG
     971        pPEDll->AddRef(getModuleName());
     972#else
     973        pPEDll->AddRef();
     974#endif
     975        if (pPEDll->attachProcess() == FALSE)
     976        {
     977            dprintf(("attachProcess failed!"));
     978            delete pPEDll;
     979            errorState = ERROR_INTERNAL;
     980            return NULL;
     981        }
     982        pDll = (Win32DllBase*)pPEDll;
     983    }
     984
     985    dprintf(("**********************************************************************"));
     986    dprintf(("**********************  Finished Loading Module %s ", szFullname));
     987    dprintf(("**********************************************************************"));
     988    return pDll;
     989}
     990
     991
     992/**
     993 * Resolve an import by symbol name.
     994 *
     995 * @returns 0 on success, error code on failure.
     996 * @param   pModule     Pointer to module.
     997 * @param   uOrdinal    Ordinal of the symbol to import.
     998 * @param   ppvAddr     Where to store the symbol address.
     999 * @remark  This should be in base class and shared with the peldr.
     1000 */
     1001ULONG Win32Pe2LxImage::importsByOrdinal(Win32ImageBase *pModule, unsigned uOrdinal, void **ppvAddr)
     1002{
     1003    void *pfn;
     1004    pfn = (void*)pModule->getApi(uOrdinal);
     1005    if (pfn)
     1006    {
     1007        dprintf(("Win32Pe2LxImage::importsByOrdinal: *%p=%p %s!%d\n", ppvAddr, pfn, pModule->getModuleName(), uOrdinal));
     1008        *ppvAddr = pfn;
     1009        return 0;
     1010    }
     1011
     1012    dprintf(("Win32Pe2LxImage::importsByOrdinal: %s!%u\n", pModule->getModuleName(), uOrdinal));
     1013    DebugInt3();
     1014    /** @todo: missing api */
     1015    *ppvAddr = NULL;
     1016    return LDRERROR_IMPORTS;
     1017}
     1018
     1019
     1020/**
     1021 * Resolve an import by symbol name.
     1022 *
     1023 * @returns 0 on success, error code on failure.
     1024 * @param   pModule     Pointer to module.
     1025 * @param   pszSymName  Name of symbol to import.
     1026 * @param   ppvAddr     Where to store the symbol address.
     1027 * @remark  This should be in base class and shared with the peldr.
     1028 */
     1029ULONG Win32Pe2LxImage::importsByName(Win32ImageBase *pModule, const char *pszSymName, void **ppvAddr)
     1030{
     1031    void *pfn;
     1032    pfn = (void*)pModule->getApi((char*)pszSymName);
     1033    if (pfn)
     1034    {
     1035        dprintf(("Win32Pe2LxImage::importsByName: *%p=%p %s!%s\n", ppvAddr, pfn, pModule->getModuleName(), pszSymName));
     1036        *ppvAddr = pfn;
     1037        return 0;
     1038    }
     1039
     1040    dprintf(("Win32Pe2LxImage::importsByName: %s!%s\n", pModule->getModuleName(), pszSymName));
     1041    DebugInt3();
     1042    /** @todo: missing api */
     1043    *ppvAddr = NULL;
     1044    return LDRERROR_IMPORTS;
     1045}
     1046
     1047
     1048/**
    6901049 * Frees memory used by this object.
    6911050 * When an exception is to be thrown, this function is called first to clean up
     
    7111070 * Converts a RVA into a pointer.
    7121071 * @returns   Pointer matching the given RVA, NULL on error.
    713  * @param     ulRVA  An address relative to the imagebase of the original PE image.
    714  *                   If this is 0UL NULL is returned.
     1072 * @param     ulRVA     An address relative to the imagebase of the original PE image.
     1073 *                      If this is 0UL NULL is returned.
     1074 * @param     fOverride If set the ulRVA doesn't have to be inside the image.
    7151075 * @sketch    DEBUG: validate state, paSections != NULL
    7161076 *            IF ulRVA is 0 THEN return NULL
     
    7241084 *            RVA == 0 is ignored.
    7251085 */
    726 PVOID  Win32Pe2LxImage::getPointerFromRVA(ULONG ulRVA)
    727 {
    728     int i;
    729 
     1086void *  Win32Pe2LxImage::getPointerFromRVA(ULONG ulRVA, BOOL fOverride)
     1087{
    7301088    #ifdef DEBUG
    7311089    if (paSections == NULL)
     
    7391097        return NULL;
    7401098
    741     i = 0;
     1099    int i = 0;
    7421100    while (i < cSections &&
    7431101           (paSections[i].ulRVA > ulRVA || paSections[i].ulRVA + paSections[i].cbVirtual <= ulRVA)) /* ALIGN on page too? */
    7441102        i++;
    745 
    7461103    if (i >= cSections)
     1104    {
     1105        /* This isn't good, but it's required to support api overrides. */
     1106        if (fOverride)
     1107            return (char*)hinstance + ulRVA;
    7471108        return NULL;
     1109    }
    7481110
    7491111    return (PVOID)(ulRVA - paSections[i].ulRVA + paSections[i].ulAddress);
     1112}
     1113
     1114
     1115/** Converts a pointer to an RVA for the loaded image.
     1116 * @remark Because of export overriding addresses outside the image must be supported.
     1117 */
     1118ULONG Win32Pe2LxImage::getRVAFromPointer(void *pv, BOOL fOverride/* = FALSE*/)
     1119{
     1120    #ifdef DEBUG
     1121    if (paSections == NULL)
     1122    {
     1123        eprintf(("Win32Pe2LxImage::getPointerFromRVA: paSections is NULL!\n"));
     1124        return NULL;
     1125    }
     1126    #endif
     1127
     1128    if (pv == 0UL)
     1129        return NULL;
     1130
     1131    int i = 0;
     1132    while (i < cSections &&
     1133           (paSections[i].ulAddress > (ULONG)pv || paSections[i].ulAddress + paSections[i].cbVirtual <= (ULONG)pv)) /* ALIGN on page too? */
     1134        i++;
     1135    if (i >= cSections)
     1136    {
     1137        /* This isn't good, but it's required to support api overrides. */
     1138        if (fOverride)
     1139            return (ULONG)pv - (ULONG)hinstance;
     1140        return NULL;
     1141    }
     1142
     1143    return (ULONG)pv - paSections[i].ulAddress + paSections[i].ulRVA;
    7501144}
    7511145
     
    8431237
    8441238
    845 /**
    846  * Gets pointer to an exported procedure by procedure name.
    847  * @returns   Address of exported procedure. 0UL if not found.
    848  * @param     name  Exported procedure name.
    849  * @status    completely implemented.
    850  * @author    Sander van Leeuwen
    851  * @remark
    852  */
    853 ULONG Win32Pe2LxImage::getApi(char *name)
    854 {
    855     APIRET      rc;
    856     ULONG       ulApiAddr;
    857 
    858     rc = DosQueryProcAddr(hmod, 0, name, (PFN *)&ulApiAddr);
    859     return rc == NO_ERROR ? ulApiAddr : 0;
    860 }
    861 
    862 
    863 /**
    864  * Gets pointer to an exported procedure by ordinal.
    865  * @returns   Pointer to an exported procedure. 0UL if not found.
    866  * @param     ordinal  Export ordinal number.
    867  * @status    completely implemented.
    868  * @author    Sander van Leeuwen
    869  * @remark    FIXME:
    870  *            This function should be implemented for both Exe and Dll images!
    871  *            It could be done similar in both peldr image and pe2lx images by
    872  *            accessing PE structures.
    873  */
    874 ULONG Win32Pe2LxImage::getApi(int ordinal)
    875 {
    876     APIRET      rc;
    877     ULONG       ulApiAddr;
    878 
    879     rc = DosQueryProcAddr(hmod, ordinal, NULL, (PFN *)&ulApiAddr);
    880 
    881     return rc == NO_ERROR ? ulApiAddr : 0;
    882 }
  • trunk/src/kernel32/winimagepe2lx.h

    r9537 r10397  
    1 /* $Id: winimagepe2lx.h,v 1.9 2002-12-20 11:39:42 sandervl Exp $ */
     1/* $Id: winimagepe2lx.h,v 1.10 2004-01-15 10:39:13 sandervl Exp $ */
    22
    33/*
     
    4343    virtual DWORD   init();
    4444
    45     /** @cat Exports */
    46     virtual ULONG   getApi(char *name);
    47     virtual ULONG   getApi(int ordinal);
    48 
    4945    /** @cat Queries */
    5046    /** Get the OS/2 module handle.
     
    5652    ULONG           getSections();
    5753    ULONG           setSectionRVAs();
     54    ULONG           doResources();
     55    ULONG           doTLS();
     56    ULONG           doImports();
     57    Win32ImageBase *importsGetModule(const char *pszModName);
     58    Win32DllBase   *importsLoadModule(const char *pszModName);
     59    ULONG           importsByOrdinal(Win32ImageBase *pModule, unsigned uOrdinal, void **ppvAddr);
     60    ULONG           importsByName(Win32ImageBase *pModule, const char *pszSymName, void **ppvAddr);
    5861    VOID            cleanup();
    5962
     
    6164    /** @cat RVA -> pointer */
    6265    /* these should be moved to winimagebase some day... */
    63     PVOID           getPointerFromRVA(ULONG ulRVA);
     66    void *          getPointerFromRVA(ULONG ulRVA, BOOL fOverride = FALSE);
     67    ULONG           getRVAFromPointer(void *pv, BOOL fOverride = FALSE);
    6468    PVOID           getPointerFromPointer(PVOID pv);
    6569    LONG            getSectionIndexFromRVA(ULONG ulRVA);
    6670    BOOL            validateRealPointer(PVOID pv);
    6771
    68     PSECTION            paSections; /* Used by getPointerFromRVA and created by getSections and
    69                                      * setSectionRVAs. */
    70     WORD                cSections;  /* Count of entires in the section array (paSection) */
     72    /** Used by getPointerFromRVA and created by getSections and setSectionRVAs. */
     73    PSECTION            paSections;
     74    /** Count of entires in the section array (paSection) */
     75    int                 cSections;
    7176
    7277    /** @cat Misc */
    73     PIMAGE_NT_HEADERS   pNtHdrs;    /* Pointer to NT headers. */
    74     BOOL                fWin32k;    /* flag which indicates wether this is a Win32k loaded
    75                                      * module (TRUE) or and Pe2Lx module (FALSE). */
    76     HMODULE             hmod;       /* OS/2 handle of the module. */
    77     BOOL                fDll;       /* Set by Win32Pe2LxDll. */
     78    /** Pointer to NT headers. */
     79    PIMAGE_NT_HEADERS   pNtHdrs;
     80    /** Flag which indicates wether this is a Win32k loaded
     81     * module (TRUE) or and Pe2Lx module (FALSE). */
     82    BOOL                fWin32k;
     83    /** OS/2 handle of the module. */
     84    HMODULE             hmod;
     85    /** Set by Win32Pe2LxDll. */
     86    BOOL                fDll;
    7887};
    7988
  • trunk/src/kernel32/winimagepeldr.cpp

    r10001 r10397  
    1 /* $Id: winimagepeldr.cpp,v 1.108 2003-04-09 12:24:45 sandervl Exp $ */
     1/* $Id: winimagepeldr.cpp,v 1.109 2004-01-15 10:39:13 sandervl Exp $ */
    22
    33/*
     
    66 * Copyright 1998-2000 Sander van Leeuwen (sandervl@xs4all.nl)
    77 * Copyright 1998 Knut St. Osmundsen
     8 * Copyright 2003 Innotek Systemberatung GmbH (sandervl@innotek.de)
     9 *
    810 *
    911 * Project Odin Software License can be found in LICENSE.TXT
     
    110112    nrsections(0), imageSize(0), dwFlags(0), section(NULL),
    111113    imageVirtBase(-1), realBaseAddress(0), imageVirtEnd(0),
    112     nrNameExports(0), nrOrdExports(0), nameexports(NULL), ordexports(NULL),
    113     memmap(NULL), pFixups(NULL), dwFixupSize(0), curnameexport(NULL), curordexport(NULL),
    114     nrOrdExportsRegistered(0), peview(NULL)
    115 {
    116     HFILE  dllfile;
     114    memmap(NULL), pFixups(NULL), dwFixupSize(0), peview(NULL),
     115    originalBaseAddress(0)
     116{
     117    HFILE                 dllfile;
    117118
    118119    fIsPEImage = TRUE;
     
    166167    }
    167168
    168     if(nameexports)
    169         free(nameexports);
    170 
    171     if(ordexports)
    172         free(ordexports);
    173 
    174169    if(section)
    175170        free(section);
     
    181176 ULONG  filesize, ulRead, ulNewPos;
    182177 PIMAGE_SECTION_HEADER psh;
    183  IMAGE_SECTION_HEADER sh;
     178 IMAGE_SECTION_HEADER  sh;
     179 IMAGE_OPTIONAL_HEADER oh;
     180 IMAGE_FILE_HEADER     fh;
    184181 IMAGE_TLS_DIRECTORY *tlsDir = NULL;
    185182 int    nSections, i;
     
    245242        oh.SizeOfImage = OSLibDosGetFileSize(hFile, NULL);
    246243    }
     244    Characteristics = fh.Characteristics;
     245
     246    //save original base address of image
     247    originalBaseAddress = oh.ImageBase;
    247248
    248249    imageSize = oh.SizeOfImage;
     
    264265        setFullPath(szFullPath);
    265266    }
     267
     268    //Use pointer to image header as module handle now. Some apps needs this
     269#ifdef COMMIT_ALL
     270    commitPage(realBaseAddress, FALSE, SINGLE_PAGE);
     271#endif
     272    hinstance = (HINSTANCE)realBaseAddress;
     273
     274    //Calculate address of optional header
     275    poh = (PIMAGE_OPTIONAL_HEADER)OPTHEADEROFF(hinstance);
    266276
    267277    if(!(fh.Characteristics & IMAGE_FILE_EXECUTABLE_IMAGE)) {//not valid
     
    373383                continue;
    374384            }
    375             if(IsSectionType(peview, &psh[i], IMAGE_DIRECTORY_ENTRY_DEBUG))
    376             {
    377                 dprintf((LOG, ".rdebug" ));
    378                 addSection(SECTION_DEBUG,  psh[i].PointerToRawData,
    379                            psh[i].SizeOfRawData, psh[i].VirtualAddress + oh.ImageBase,
    380                            psh[i].Misc.VirtualSize, psh[i].Characteristics);
    381                 continue;
    382             }
    383385            if(IsSectionType(peview, &psh[i], IMAGE_DIRECTORY_ENTRY_IMPORT))
    384386            {
     
    406408                continue;
    407409            }
     410            /* bird: Do this test as late as possible since marking a section as debug
     411             *       because it the section will not be preloaded if marked SECTION_DEBUG
     412             *       causeing a lot of annoying page faults when all should be preloaded.
     413             *       A debug section may contain more than just the debug directory.
     414             *
     415             * IIRC the debug directory doesn't contain the debug info, it's a table telling
     416             * raw file offsets of the different debug types. It's never been any custom of
     417             * linkers to put debug info into loadable segments/sections/objects, so I've some
     418             * difficulty seeing why we're doing this in the first place.
     419             *
     420             * Why aren't we just using a general approach, which trust the section flags and
     421             * only precommits the tree directories we use (fixups/imports/exports)?
     422             */
     423            if(IsSectionType(peview, &psh[i], IMAGE_DIRECTORY_ENTRY_DEBUG))
     424            {
     425                dprintf((LOG, ".rdebug" ));
     426                addSection(SECTION_DEBUG,  psh[i].PointerToRawData,
     427                           psh[i].SizeOfRawData, psh[i].VirtualAddress + oh.ImageBase,
     428                           psh[i].Misc.VirtualSize, psh[i].Characteristics);
     429                continue;
     430            }
    408431            if(!(psh[i].Characteristics & IMAGE_SCN_MEM_WRITE)) { //read only data section
    409432                dprintf((LOG, "Read Only Data Section" ));
     
    474497        pFixups     = (PIMAGE_BASE_RELOCATION)ImageDirectoryOffset(peview, IMAGE_DIRECTORY_ENTRY_BASERELOC);
    475498        dwFixupSize = ImageDirectorySize(peview, IMAGE_DIRECTORY_ENTRY_BASERELOC);
    476         commitPage((ULONG)pFixups, FALSE);
    477     }
    478 
    479     //Use pointer to image header as module handle now. Some apps needs this
    480     hinstance = (HINSTANCE)realBaseAddress;
     499        /* commit complete section to avoid getting exceptions inside setFixups(). */
     500        commitPage((ULONG)pFixups, FALSE, COMPLETE_SECTION);
     501    }
    481502
    482503    if(!(dwFlags & FLAG_PELDR_LOADASDATAFILE))
     
    811832    }
    812833    if(fPageCmd == COMPLETE_SECTION && (section && section->type == SECTION_DEBUG)) {//ignore
     834#ifdef DEBUG
     835        /* check for env. var. ODIN_PELDR_COMMIT_ALL, committing it anyway if that is set. */
     836        static int f = -1;
     837        if (f == -1)
     838            f = (getenv("ODIN_PELDR_COMMIT_ALL") != NULL);
     839        if (!f)
     840#endif
    813841        return TRUE;
    814842    }
     
    931959BOOL Win32PeLdrImage::allocSections(ULONG reservedMem)
    932960{
    933  APIRET rc;
    934  ULONG  baseAddress;
     961    APIRET rc;
     962    ULONG  baseAddress;
    935963
    936964    realBaseAddress = 0;
    937965
    938966    //Allocated in by pe.exe
    939     if(reservedMem && reservedMem == oh.ImageBase) {
    940         realBaseAddress = oh.ImageBase;
     967    if(reservedMem && reservedMem == originalBaseAddress) {
     968        realBaseAddress = originalBaseAddress;
    941969        return TRUE;
    942970    }
    943971
    944972    //SvL: We don't care where the image is loaded for resource lookup
    945     if(fh.Characteristics & IMAGE_FILE_RELOCS_STRIPPED && !(dwFlags & FLAG_PELDR_LOADASDATAFILE)) {
     973    if(Characteristics & IMAGE_FILE_RELOCS_STRIPPED && !(dwFlags & FLAG_PELDR_LOADASDATAFILE)) {
    946974        return allocFixedMem(reservedMem);
    947975    }
     
    10291057    }
    10301058
    1031     if(oh.ImageBase < 512*1024*1024) {
     1059    if(originalBaseAddress < 512*1024*1024) {
    10321060        fLowMemory = TRUE;
    10331061    }
     
    10371065
    10381066        dprintf((LOG, "DosAllocMem returned %x", address ));
    1039         if(address + FALLOC_SIZE >= oh.ImageBase) {
    1040             if(address > oh.ImageBase) {//we've passed it!
     1067        if(address + FALLOC_SIZE >= originalBaseAddress) {
     1068            if(address > originalBaseAddress) {//we've passed it!
    10411069                OSLibDosFreeMem((PVOID)address);
    10421070                break;
     
    10451073            OSLibDosFreeMem((PVOID)address);
    10461074
    1047             diff = oh.ImageBase - address;
     1075            diff = originalBaseAddress - address;
    10481076            if(diff) {
    10491077                rc = OSLibDosAllocMem((PPVOID)&address, diff, PAG_READ, fLowMemory);
     
    10781106  // Process all the image sections
    10791107  for(i=0;i<nrsections;i++) {
    1080         section[i].realvirtaddr = realBaseAddress + (section[i].virtaddr - oh.ImageBase);
     1108        section[i].realvirtaddr = realBaseAddress + (section[i].virtaddr - originalBaseAddress);
    10811109  }
    10821110
     
    11281156 PIMAGE_BASE_RELOCATION prel = pFixups;
    11291157
    1130   if(realBaseAddress == oh.ImageBase || fh.Characteristics & IMAGE_FILE_RELOCS_STRIPPED) {
     1158  if(realBaseAddress == originalBaseAddress || Characteristics & IMAGE_FILE_RELOCS_STRIPPED) {
    11311159        return(TRUE);
    11321160  }
     
    12261254 ULONG count;
    12271255
    1228   if(fh.Characteristics & IMAGE_FILE_RELOCS_STRIPPED) {
     1256  if(Characteristics & IMAGE_FILE_RELOCS_STRIPPED) {
    12291257        return(TRUE);
    12301258  }
     
    12801308    fixup   = (ULONG *)(fixupaddr + realBaseAddress);
    12811309    orgaddr = *fixup;
    1282 //  dprintf((LOG, "AddOff32Fixup 0x%x org 0x%x -> new 0x%x", fixup, orgaddr, realBaseAddress + (*fixup - oh.ImageBase)));
    1283     *fixup  = realBaseAddress + (*fixup - oh.ImageBase);
     1310//  dprintf((LOG, "AddOff32Fixup 0x%x org 0x%x -> new 0x%x", fixup, orgaddr, realBaseAddress + (*fixup - originalBaseAddress)));
     1311    *fixup  = realBaseAddress + (*fixup - originalBaseAddress);
    12841312}
    12851313//******************************************************************************
     
    12931321    orgaddr = *fixup;
    12941322    if(fHighFixup) {
    1295         *fixup  += (USHORT)((realBaseAddress - oh.ImageBase) >> 16);
     1323        *fixup  += (USHORT)((realBaseAddress - originalBaseAddress) >> 16);
    12961324//        dprintf((LOG, "AddOff16FixupH 0x%x org 0x%x -> new 0x%x", fixup, orgaddr, *fixup));
    12971325    }
    12981326    else {
    1299         *fixup  += (USHORT)((realBaseAddress - oh.ImageBase) & 0xFFFF);
     1327        *fixup  += (USHORT)((realBaseAddress - originalBaseAddress) & 0xFFFF);
    13001328//        dprintf((LOG, "AddOff16FixupL 0x%x org 0x%x -> new 0x%x", fixup, orgaddr, *fixup));
    13011329    }
     
    13391367        char *code = (char *)_cmalloc(sizeof(missingapicode));
    13401368
     1369#ifdef DEBUG
     1370        MissingApiOrd(WinImage->getModuleName(), getModuleName(), ordinal);
     1371#endif
    13411372        memcpy(code, missingapicode, sizeof(missingapicode));
    13421373        *(DWORD *)&code[MISSINGOFFSET_PUSHIMPORTIMAGE] = (DWORD)getModuleName();
     
    13671398        char *code = (char *)_cmalloc(sizeof(missingapicode));
    13681399
     1400#ifdef DEBUG
     1401        MissingApiName(WinImage->getModuleName(), getModuleName(), impname);
     1402#endif
     1403
    13691404        memcpy(code, missingapicode, sizeof(missingapicode));
    13701405        *(DWORD *)&code[MISSINGOFFSET_PUSHIMPORTIMAGE] = (DWORD)getModuleName();
     
    14001435  if((ped = (PIMAGE_EXPORT_DIRECTORY)ImageDirectoryOffset
    14011436     (peview, IMAGE_DIRECTORY_ENTRY_EXPORT)) != NULL &&
    1402      GetSectionHdrByImageDir(peview, IMAGE_DIRECTORY_ENTRY_EXPORT, &sh) ) 
     1437     GetSectionHdrByImageDir(peview, IMAGE_DIRECTORY_ENTRY_EXPORT, &sh) )
    14031438  {
    14041439
     
    14101445    ptrAddress = (ULONG *)((ULONG)ped->AddressOfFunctions +
    14111446                            (ULONG)peview);
    1412     nrOrdExports  = ped->NumberOfFunctions;
    1413     nrNameExports = ped->NumberOfNames;
     1447    int nrOrdExports  = ped->NumberOfFunctions;
     1448    int nrNameExports = ped->NumberOfNames;
    14141449
    14151450    int   ord, RVAExport;
     
    14231458
    14241459        /* forwarder? ulRVA within export directory. */
    1425         if(RVAExport > oh.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress &&
    1426            RVAExport < oh.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress
    1427                        + oh.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size)
     1460        if(RVAExport > poh->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress &&
     1461           RVAExport < poh->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress
     1462                       + poh->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size)
    14281463        {
    1429             fForwarder = AddForwarder(oh.ImageBase + RVAExport, name, ord);
     1464            fForwarder = loadForwarder(originalBaseAddress + RVAExport, name, ord);
    14301465        }
    14311466        if(!fForwarder) {
    1432             //points to code (virtual address relative to oh.ImageBase
    1433             AddNameExport(oh.ImageBase + RVAExport, name, ord);
     1467            //points to code (virtual address relative to originalBaseAddress
    14341468            dprintf((LOG, "address 0x%x %s @%d (0x%08x)", RVAExport, name, ord, realBaseAddress + RVAExport));
    14351469        }
     
    14411475        RVAExport = ptrAddress[i];
    14421476        /* forwarder? ulRVA within export directory. */
    1443         if(RVAExport > oh.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress &&
    1444            RVAExport < oh.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress
    1445                        + oh.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size)
     1477        if(RVAExport > poh->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress &&
     1478           RVAExport < poh->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress
     1479                       + poh->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size)
    14461480        {
    1447             fForwarder = AddForwarder(oh.ImageBase + RVAExport, NULL, ord);
     1481            fForwarder = loadForwarder(originalBaseAddress + RVAExport, NULL, ord);
    14481482        }
    14491483        if(!fForwarder && RVAExport) {
    1450             //points to code (virtual address relative to oh.ImageBase
     1484            //points to code (virtual address relative to originalBaseAddress
    14511485            dprintf((LOG, "ord %d at 0x%08x (0x%08x)", ord, RVAExport, realBaseAddress + RVAExport));
    1452             AddOrdExport(oh.ImageBase + RVAExport, ord);
    14531486        }
    14541487    }
     
    14651498//******************************************************************************
    14661499//******************************************************************************
    1467 void Win32PeLdrImage::AddNameExport(ULONG virtaddr, char *apiname, ULONG ordinal, BOOL fAbsoluteAddress)
    1468 {
    1469     ULONG nsize;
    1470     int iApiNameLength = strlen(apiname);
    1471 
    1472     if(nameexports == NULL) {
    1473         // think of a maximum of bytes per export name,
    1474         // verify if this is true for MFC-DLLs, etc.
    1475         nameExportSize = nrNameExports * (sizeof(NameExport) + 32);
    1476 
    1477         nameexports   = (NameExport *)malloc(nameExportSize);
    1478         curnameexport = nameexports;
    1479     }
    1480     nsize = (ULONG)curnameexport - (ULONG)nameexports;
    1481     if(nsize + sizeof(NameExport) + iApiNameLength > nameExportSize) {
    1482         nameExportSize += 4096;
    1483         char *tmp = (char *)nameexports;
    1484         nameexports = (NameExport *)malloc(nameExportSize);
    1485         memcpy(nameexports, tmp, nsize);
    1486         curnameexport = (NameExport *)((ULONG)nameexports + nsize);
    1487         free(tmp);
    1488     }
    1489     if(fAbsoluteAddress) {//forwarders use absolute address
    1490         curnameexport->virtaddr = virtaddr;
    1491     }
    1492     else curnameexport->virtaddr = realBaseAddress + (virtaddr - oh.ImageBase);
    1493     curnameexport->ordinal  = ordinal;
    1494     *(ULONG *)curnameexport->name = 0;
    1495 
    1496     curnameexport->nlength = iApiNameLength + 1;
    1497     memcpy(curnameexport->name, apiname,  curnameexport->nlength);
    1498 
    1499     if(curnameexport->nlength < sizeof(curnameexport->name))
    1500         curnameexport->nlength = sizeof(curnameexport->name);
    1501 
    1502     curnameexport = (NameExport *)((ULONG)curnameexport->name + curnameexport->nlength);
    1503 }
    1504 //******************************************************************************
    1505 //******************************************************************************
    1506 void Win32PeLdrImage::AddOrdExport(ULONG virtaddr, ULONG ordinal, BOOL fAbsoluteAddress)
    1507 {
    1508     if(ordexports == NULL) {
    1509         ordexports   = (OrdExport *)malloc(nrOrdExports * sizeof(OrdExport));
    1510         curordexport = ordexports;
    1511     }
    1512     if(fAbsoluteAddress) {//forwarders use absolute address
    1513         curordexport->virtaddr = virtaddr;
    1514     }
    1515     else curordexport->virtaddr = realBaseAddress + (virtaddr - oh.ImageBase);
    1516 
    1517     curordexport->ordinal  = ordinal;
    1518     curordexport++;
    1519     nrOrdExportsRegistered++;
    1520 }
    1521 //******************************************************************************
    1522 //******************************************************************************
    1523 BOOL Win32PeLdrImage::AddForwarder(ULONG virtaddr, char *apiname, ULONG ordinal)
    1524 {
    1525     char         *forward = (char *)(realBaseAddress + (virtaddr - oh.ImageBase));
     1500BOOL Win32PeLdrImage::loadForwarder(ULONG virtaddr, char *apiname, ULONG ordinal)
     1501{
     1502    char         *forward = (char *)(realBaseAddress + (virtaddr - originalBaseAddress));
    15261503    char         *forwarddll, *forwardapi;
    15271504    Win32DllBase *WinDll;
     
    15691546
    15701547    if(apiname) {
    1571         dprintf((LOG, "address 0x%x %s @%d (0x%08x) forwarder %s.%s", virtaddr - oh.ImageBase, apiname, ordinal, virtaddr, forwarddll, forwardapi));
    1572         AddNameExport(exportaddr, apiname, ordinal, TRUE);
     1548        dprintf((LOG, "address 0x%x %s @%d (0x%08x->0x%08x) forwarder %s.%s", virtaddr - originalBaseAddress, apiname, ordinal, virtaddr, exportaddr, forwarddll, forwardapi));
    15731549    }
    15741550    else {
    1575         dprintf((LOG, "address 0x%x @%d (0x%08x) forwarder %s.%s", virtaddr - oh.ImageBase, ordinal, virtaddr, forwarddll, forwardapi));
    1576         AddOrdExport(exportaddr, ordinal, TRUE);
    1577     }
    1578     return TRUE;
     1551        dprintf((LOG, "address 0x%x @%d (0x%08x->0x%08x) forwarder %s.%s", virtaddr - originalBaseAddress, ordinal, virtaddr, exportaddr, forwarddll, forwardapi));
     1552    }
     1553    return (exportaddr != 0);
    15791554}
    15801555//******************************************************************************
     
    16061581        ULONG  hInstanceNewDll;
    16071582
    1608         char *dot = strchr(modname, '.');
    1609         if(dot == NULL) {
    1610             strcat(modname, DLL_EXTENSION);
    1611         }
    16121583        rc = DosLoadModule(szModuleFailure, sizeof(szModuleFailure), modname, (HMODULE *)&hInstanceNewDll);
    16131584        if(rc) {
     
    16881659    IMAGE_SECTION_HEADER     shID;
    16891660    IMAGE_SECTION_HEADER     shExtra = {0};
    1690     PIMAGE_OPTIONAL_HEADER   pOH;
    16911661    int    i,j, nrPages;
    16921662    BOOL   fBorland = 0;
     
    17781748    /* 2) functions */
    17791749    pszCurModule = pszModules;
    1780     pOH = (PIMAGE_OPTIONAL_HEADER)OPTHEADEROFF(peview);
    17811750    for (i = 0; i < cModules; i++)
    17821751    {
     
    17921761               (ULONG)pID[i].u.OriginalFirstThunk < shID.VirtualAddress ||
    17931762               (ULONG)pID[i].u.OriginalFirstThunk >= shID.VirtualAddress + max(shID.Misc.VirtualSize, shID.SizeOfRawData) ||
    1794                (ULONG)pID[i].u.OriginalFirstThunk >= pOH->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress &&
    1795                (ULONG)pID[i].u.OriginalFirstThunk < sizeof(*pID)*cModules + pOH->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress)
     1763               (ULONG)pID[i].u.OriginalFirstThunk >= poh->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress &&
     1764               (ULONG)pID[i].u.OriginalFirstThunk < sizeof(*pID)*cModules + poh->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress)
    17961765            {
    17971766                fBorland = TRUE;
     
    18051774
    18061775        //  b) check if RVA ok
    1807         if (!(pulImport > 0 && (ULONG)pulImport < pOH->SizeOfImage)) {
     1776        if (!(pulImport > 0 && (ULONG)pulImport < poh->SizeOfImage)) {
    18081777            dprintf((LOG, "Invalid RVA %x", pulImport ));
    18091778            break;
     
    18311800            }
    18321801            else {
     1802
    18331803                WinDll = loadDll(pszCurModule);
    18341804                if(WinDll == NULL) {
     
    19011871        }
    19021872        //SvL: And restore original protection flags
    1903         ulCurFixup = (ULONG)pID[i].FirstThunk + pOH->ImageBase;
     1873        ulCurFixup = (ULONG)pID[i].FirstThunk + poh->ImageBase;
    19041874        DosSetMem((PVOID)(ulCurFixup & ~0xfff), PAGE_SIZE*nrPages, section->pageflags);
    19051875
     
    19401910}
    19411911//******************************************************************************
    1942 //******************************************************************************
    1943 NameExport *Win32PeLdrImage::findApi(char *name)
    1944 {
    1945   ULONG       apiaddr, i, apilen;
    1946   char       *apiname;
    1947   char        tmp[4];
    1948   NameExport *curexport;
    1949   ULONG       ulAPIOrdinal;                      /* api requested by ordinal */
    1950 
    1951     apilen = strlen(name) + 1;
    1952     if(apilen < 4)
    1953     {
    1954         *(ULONG *)tmp = 0;
    1955         strcpy(tmp, name);
    1956         apiname = tmp;
    1957         apilen  = 4;
    1958     }
    1959     else  apiname = name;
    1960 
    1961     curexport = nameexports;
    1962     for(i=0; i<nrNameExports; i++)
    1963     {
    1964         if(apilen == curexport->nlength &&
    1965            *(ULONG *)curexport->name == *(ULONG *)apiname)
    1966         {
    1967             if(strcmp(curexport->name, apiname) == 0)
    1968                 return curexport;
    1969         }
    1970         curexport = (NameExport *)((ULONG)curexport->name + curexport->nlength);
    1971     }
    1972     return NULL;
    1973 }
    1974 //******************************************************************************
    1975 //******************************************************************************
    1976 ULONG Win32PeLdrImage::getApi(char *name)
    1977 {
    1978     NameExport *curexport;
    1979 
    1980     curexport = findApi(name);
    1981     if(curexport) {
    1982         return(curexport->virtaddr);
    1983     }
    1984     return 0;
    1985 }
    1986 //******************************************************************************
    1987 //Override a name export
    1988 //******************************************************************************
    1989 ULONG Win32PeLdrImage::setApi(char *name, ULONG pfnNewProc)
    1990 {
    1991     NameExport *curexport;
    1992 
    1993     curexport = findApi(name);
    1994     if(curexport) {
    1995         ULONG pfnOldProc = curexport->virtaddr;
    1996 
    1997         curexport->virtaddr = pfnNewProc;
    1998         return pfnOldProc;
    1999     }
    2000     return -1;
    2001 }
    2002 //******************************************************************************
    2003 //******************************************************************************
    2004 OrdExport *Win32PeLdrImage::findApi(int ordinal)
    2005 {
    2006  ULONG       apiaddr, i;
    2007  OrdExport  *curexport;
    2008 
    2009     curexport = ordexports;
    2010 
    2011   /* accelerated resolving of ordinal exports
    2012    * is based on the assumption the ordinal export
    2013    * table is always sorted ascending.
    2014    *
    2015    * When the step size is too small, we continue
    2016    * with the linear search.
    2017    */
    2018 
    2019   // start in the middle of the tree
    2020   i = nrOrdExportsRegistered >> 1;
    2021   int iStep = i;
    2022 
    2023   for(;;)
    2024   {
    2025     int iThisExport = curexport[i].ordinal;
    2026 
    2027     iStep >>= 1;                    // next step will be narrower
    2028 
    2029     if (iThisExport < ordinal)
    2030       i += min(iStep, (ordinal-iThisExport)); // move farther down the list
    2031     else
    2032       if (iThisExport == ordinal)   // found the export?
    2033         return &curexport[i];
    2034       else
    2035         i -= min(iStep, (iThisExport-ordinal));                 // move farther up the list
    2036 
    2037     // if we're in the direct neighbourhood search linearly
    2038     if (iStep <= 1)
    2039     {
    2040       // decide if we're to search backward or forward
    2041       if (ordinal > curexport[i].ordinal)
    2042       {
    2043         // As a certain number of exports are 0 at the end
    2044         // of the array, this case will hit fairly often.
    2045         // the last comparison will send the loop off into the
    2046         // wrong direction!
    2047 #ifdef DEBUG
    2048         if (curexport[i].ordinal == 0)
    2049         {
    2050             DebugInt3();
    2051         }
    2052 #endif
    2053 
    2054         for (;i<nrOrdExports;i++) // scan forward
    2055         {
    2056           iThisExport = curexport[i].ordinal;
    2057           if(iThisExport == ordinal)
    2058             return &curexport[i];
    2059           else
    2060             if (iThisExport > ordinal)
    2061             {
    2062               // Oops, cannot find the ordinal in the sorted list
    2063               break;
    2064             }
    2065         }
    2066       }
    2067       else
    2068       {
    2069         for (;i>=0;i--) // scan backward
    2070         {
    2071           iThisExport = curexport[i].ordinal;
    2072           if(curexport[i].ordinal == ordinal)
    2073             return &curexport[i];
    2074           else
    2075             if (iThisExport < ordinal)
    2076               // Oops, cannot find the ordinal in the sorted list
    2077               break;
    2078         }
    2079       }
    2080 
    2081       // not found yet.
    2082       break;
    2083     }
    2084   }
    2085   return NULL;
    2086 }
    2087 //******************************************************************************
    2088 //******************************************************************************
    2089 ULONG Win32PeLdrImage::getApi(int ordinal)
    2090 {
    2091     OrdExport  *curexport;
    2092     NameExport *nexport;
    2093 
    2094     curexport = findApi(ordinal);
    2095     if(curexport) {
    2096         return curexport->virtaddr;
    2097     }
    2098 
    2099     //Name exports also contain an ordinal, so check this
    2100     nexport = nameexports;
    2101     for(int i=0;i<nrNameExports;i++) {
    2102         if(nexport->ordinal == ordinal)
    2103             return(nexport->virtaddr);
    2104 
    2105         nexport = (NameExport *)((ULONG)nexport->name + nexport->nlength);
    2106     }
    2107     return(0);
    2108 }
    2109 //******************************************************************************
    2110 //Override an ordinal export
    2111 //******************************************************************************
    2112 ULONG Win32PeLdrImage::setApi(int ordinal, ULONG pfnNewProc)
    2113 {
    2114     OrdExport  *curexport;
    2115     NameExport *nexport;
    2116 
    2117     curexport = findApi(ordinal);
    2118     if(curexport) {
    2119         ULONG pfnOldProc = curexport->virtaddr;
    2120 
    2121         curexport->virtaddr = pfnNewProc;
    2122         return pfnOldProc;
    2123     }
    2124 
    2125     //Name exports also contain an ordinal, so check this
    2126     nexport = nameexports;
    2127     for(int i=0;i<nrNameExports;i++)
    2128     {
    2129         if(nexport->ordinal == ordinal) {
    2130             ULONG pfnOldProc = nexport->virtaddr;
    2131 
    2132             nexport->virtaddr = pfnNewProc;
    2133             return pfnOldProc;
    2134         }
    2135 
    2136         nexport = (NameExport *)((ULONG)nexport->name + nexport->nlength);
    2137     }
    2138     return -1;
    2139 }
    2140 //******************************************************************************
    21411912//Returns required OS version for this image
    21421913//******************************************************************************
    21431914ULONG Win32PeLdrImage::getVersion()
    21441915{
    2145     return (oh.MajorOperatingSystemVersion << 16) | oh.MinorOperatingSystemVersion;
     1916    return (poh->MajorOperatingSystemVersion << 16) | poh->MinorOperatingSystemVersion;
    21461917}
    21471918//******************************************************************************
  • trunk/src/kernel32/winimagepeldr.h

    r9997 r10397  
    1 /* $Id: winimagepeldr.h,v 1.20 2003-04-09 10:39:41 sandervl Exp $ */
     1/* $Id: winimagepeldr.h,v 1.21 2004-01-15 10:39:15 sandervl Exp $ */
    22
    33/*
     
    8585    virtual BOOL  insideModuleCode(ULONG address);
    8686
    87     virtual ULONG getApi(char *name);
    88     virtual ULONG getApi(int ordinal);
    89     virtual ULONG setApi(char *name, ULONG pfnNewProc);
    90     virtual ULONG setApi(int ordinal, ULONG pfnNewProc);
    91 
    9287    virtual ULONG getImageSize();
    9388
     
    114109     Section *findPreviousSectionByOS2Addr(ULONG addr);
    115110
    116    OrdExport *findApi(int ordinal);
    117   NameExport *findApi(char *name);
    118 
    119111        BOOL  setMemFlags();
    120112        BOOL  setFixups(PIMAGE_BASE_RELOCATION prel);
     
    125117        BOOL  processImports();
    126118        BOOL  processExports();
    127         void  AddNameExport(ULONG virtaddr, char *apiname, ULONG ordinal, BOOL fAbsoluteAddress=FALSE);
    128         void  AddOrdExport(ULONG virtaddr, ULONG ordinal, BOOL fAbsoluteAddress=FALSE);
    129         BOOL  AddForwarder(ULONG virtaddr, char *apiname, ULONG ordinal);
     119
     120        BOOL  loadForwarder(ULONG virtaddr, char *apiname, ULONG ordinal);
    130121
    131122Win32DllBase *loadDll(char *pszCurModule);
    132123
    133         IMAGE_OPTIONAL_HEADER oh;
    134         IMAGE_FILE_HEADER     fh;
    135 
    136         ULONG                 nrNameExports, nameExportSize;
    137         ULONG                 nrOrdExports;
    138         ULONG                 nrOrdExportsRegistered;
    139         NameExport           *nameexports, *curnameexport;
    140         OrdExport            *ordexports, *curordexport;
    141 
    142124        ULONG                 nrsections, imageSize, imageVirtBase, imageVirtEnd;
    143125        //OS/2 virtual base address
    144         ULONG                 realBaseAddress;
    145         Section               *section;
     126        ULONG                 realBaseAddress, originalBaseAddress;
     127        Section              *section;
     128        ULONG                 Characteristics;
    146129
    147130        //offset in executable image where real PE file starts (default 0)
Note: See TracChangeset for help on using the changeset viewer.