master
  1/**
  2 * This file has no copyright assigned and is placed in the Public Domain.
  3 * This file is part of the mingw-w64 runtime package.
  4 * No warranty is given; refer to the file DISCLAIMER.PD within this package.
  5 *
  6 * This file is derived from Microsoft implementation file delayhlp.cpp, which
  7 * is free for users to modify and derive.
  8 */
  9#ifndef WIN32_LEAN_AND_MEAN
 10#define WIN32_LEAN_AND_MEAN
 11#endif
 12#include <windows.h>
 13#include <delayimp.h>
 14
 15static size_t __strlen(const char *sz)
 16{
 17  const char *szEnd = sz;
 18  while(*szEnd++ != 0)
 19    ;
 20  return szEnd - sz - 1;
 21}
 22
 23static int __memcmp(const void *pv1,const void *pv2,size_t cb)
 24{
 25  if(!cb)
 26    return 0;
 27  while(--cb && *(char *)pv1 == *(char *)pv2) {
 28    pv1 = ((char *)pv1) + 1;
 29    pv2 = ((char *)pv2) + 1;
 30  }
 31  return *((unsigned char *)pv1) - *((unsigned char *)pv2);
 32}
 33
 34static void *__memcpy(void *pvDst,const void *pvSrc,size_t cb)
 35{
 36  void *pvRet = pvDst;
 37  while(cb--) {
 38    *(char *)pvDst = *(char *)pvSrc;
 39    pvDst = ((char *)pvDst) + 1;
 40    pvSrc = ((char *)pvSrc) + 1;
 41  }
 42  return pvRet;
 43}
 44
 45static unsigned IndexFromPImgThunkData(PCImgThunkData pitdCur,PCImgThunkData pitdBase)
 46{
 47  return (unsigned) (pitdCur - pitdBase);
 48}
 49
 50extern IMAGE_DOS_HEADER __ImageBase;
 51
 52#define PtrFromRVA(RVA)   (((PBYTE)&__ImageBase) + (RVA))
 53
 54typedef struct UnloadInfo *PUnloadInfo;
 55typedef struct UnloadInfo {
 56  PUnloadInfo puiNext;
 57  PCImgDelayDescr pidd;
 58} UnloadInfo;
 59
 60static unsigned CountOfImports(PCImgThunkData pitdBase)
 61{
 62  unsigned cRet = 0;
 63  PCImgThunkData pitd = pitdBase;
 64  while(pitd->u1.Function) {
 65    pitd++;
 66    cRet++;
 67  }
 68  return cRet;
 69}
 70
 71PUnloadInfo __puiHead = 0;
 72
 73static UnloadInfo *add_ULI(PCImgDelayDescr pidd_)
 74{
 75    UnloadInfo *ret = (UnloadInfo *) LocalAlloc(LPTR,sizeof(UnloadInfo));
 76    ret->pidd = pidd_;
 77    ret->puiNext = __puiHead;
 78    __puiHead = ret;
 79	return ret;
 80}
 81
 82static void del_ULI(UnloadInfo *p)
 83{
 84    if (p) {
 85        PUnloadInfo *ppui = &__puiHead;
 86        while(*ppui && *ppui!=p) {
 87          ppui = &((*ppui)->puiNext);
 88        }
 89        if(*ppui==p) *ppui = p->puiNext;
 90        LocalFree((void *)p);
 91    }
 92}
 93
 94typedef struct InternalImgDelayDescr {
 95  DWORD grAttrs;
 96  LPCSTR szName;
 97  HMODULE *phmod;
 98  PImgThunkData pIAT;
 99  PCImgThunkData pINT;
100  PCImgThunkData pBoundIAT;
101  PCImgThunkData pUnloadIAT;
102  DWORD dwTimeStamp;
103} InternalImgDelayDescr;
104
105typedef InternalImgDelayDescr *PIIDD;
106typedef const InternalImgDelayDescr *PCIIDD;
107
108static PIMAGE_NT_HEADERS WINAPI PinhFromImageBase(HMODULE hmod)
109{
110  return (PIMAGE_NT_HEADERS) (((PBYTE)(hmod)) + ((PIMAGE_DOS_HEADER)(hmod))->e_lfanew);
111}
112
113static void WINAPI OverlayIAT(PImgThunkData pitdDst,PCImgThunkData pitdSrc)
114{
115  __memcpy(pitdDst,pitdSrc,CountOfImports(pitdDst) * sizeof(IMAGE_THUNK_DATA));
116}
117
118static DWORD WINAPI TimeStampOfImage(PIMAGE_NT_HEADERS pinh)
119{
120  return pinh->FileHeader.TimeDateStamp;
121}
122
123static int WINAPI FLoadedAtPreferredAddress(PIMAGE_NT_HEADERS pinh,HMODULE hmod)
124{
125  return ((UINT_PTR)(hmod)) == pinh->OptionalHeader.ImageBase;
126}
127
128#if(defined(_X86_) && !defined(__x86_64))
129#undef InterlockedExchangePointer
130#define InterlockedExchangePointer(Target,Value) (PVOID)(LONG_PTR)InterlockedExchange((PLONG)(Target),(LONG)(LONG_PTR)(Value))
131/*typedef unsigned long *PULONG_PTR;*/
132#endif
133
134FARPROC WINAPI __delayLoadHelper2(PCImgDelayDescr pidd,FARPROC *ppfnIATEntry);
135
136FARPROC WINAPI __delayLoadHelper2(PCImgDelayDescr pidd,FARPROC *ppfnIATEntry)
137{
138  InternalImgDelayDescr idd = {
139    pidd->grAttrs,(LPCTSTR) PtrFromRVA(pidd->rvaDLLName),(HMODULE *) PtrFromRVA(pidd->rvaHmod),
140    (PImgThunkData) PtrFromRVA(pidd->rvaIAT), (PCImgThunkData) PtrFromRVA(pidd->rvaINT),
141    (PCImgThunkData) PtrFromRVA(pidd->rvaBoundIAT), (PCImgThunkData) PtrFromRVA(pidd->rvaUnloadIAT),
142    pidd->dwTimeStamp};
143  DelayLoadInfo dli = {
144    sizeof(DelayLoadInfo),pidd,ppfnIATEntry,idd.szName,{ 0, { NULL } },0,0,0
145  };
146  HMODULE hmod;
147  unsigned iIAT, iINT;
148  PCImgThunkData pitd;
149  FARPROC pfnRet;
150  
151  if(!(idd.grAttrs & dlattrRva)) {
152    PDelayLoadInfo rgpdli[1] = { &dli};
153    RaiseException(VcppException(ERROR_SEVERITY_ERROR,ERROR_INVALID_PARAMETER),0,1,(PULONG_PTR)(rgpdli));
154    return 0;
155  }
156  hmod = *idd.phmod;
157  iIAT = IndexFromPImgThunkData((PCImgThunkData)(ppfnIATEntry),idd.pIAT);
158  iINT = iIAT;
159  pitd = &(idd.pINT[iINT]);
160
161  dli.dlp.fImportByName = !IMAGE_SNAP_BY_ORDINAL(pitd->u1.Ordinal);
162  if(dli.dlp.fImportByName)
163    dli.dlp.szProcName =
164      (LPCSTR)
165      (
166        ((PIMAGE_IMPORT_BY_NAME) PtrFromRVA(
167        				     (RVA)((UINT_PTR)(pitd->u1.AddressOfData))
168        				   )
169        )->Name
170      );
171  else dli.dlp.dwOrdinal = (DWORD)(IMAGE_ORDINAL(pitd->u1.Ordinal));
172  pfnRet = NULL;
173  if(__pfnDliNotifyHook2) {
174    pfnRet = ((*__pfnDliNotifyHook2)(dliStartProcessing,&dli));
175    if(pfnRet!=NULL) goto HookBypass;
176  }
177  if(hmod==0) {
178    if(__pfnDliNotifyHook2)
179      hmod = (HMODULE) (((*__pfnDliNotifyHook2)(dliNotePreLoadLibrary,&dli)));
180    if(hmod==0) hmod = LoadLibraryA(dli.szDll);
181    if(hmod==0) {
182      dli.dwLastError = GetLastError();
183      if(__pfnDliFailureHook2)
184        hmod = (HMODULE) ((*__pfnDliFailureHook2)(dliFailLoadLib,&dli));
185      if(hmod==0) {
186	PDelayLoadInfo rgpdli[1] = { &dli};
187	RaiseException(VcppException(ERROR_SEVERITY_ERROR,ERROR_MOD_NOT_FOUND),0,1,(PULONG_PTR)(rgpdli));
188	return dli.pfnCur;
189      }
190    }
191    HMODULE hmodT = (HMODULE)(InterlockedExchangePointer((PVOID *) idd.phmod,(PVOID)(hmod)));
192    if(hmodT!=hmod) {
193      if(pidd->rvaUnloadIAT) add_ULI(pidd);
194    } else FreeLibrary(hmod);
195  }
196  dli.hmodCur = hmod;
197  if(__pfnDliNotifyHook2) pfnRet = (*__pfnDliNotifyHook2)(dliNotePreGetProcAddress,&dli);
198  if(pfnRet==0) {
199    if(pidd->rvaBoundIAT && pidd->dwTimeStamp) {
200      PIMAGE_NT_HEADERS pinh = (PIMAGE_NT_HEADERS) (PinhFromImageBase(hmod));
201      if(pinh->Signature==IMAGE_NT_SIGNATURE &&
202	TimeStampOfImage(pinh)==idd.dwTimeStamp &&
203	FLoadedAtPreferredAddress(pinh,hmod)) {
204	  pfnRet = (FARPROC) ((UINT_PTR)(idd.pBoundIAT[iIAT].u1.Function));
205	  if(pfnRet!=0) goto SetEntryHookBypass;
206      }
207    }
208    pfnRet = GetProcAddress(hmod,dli.dlp.szProcName);
209  }
210  if(!pfnRet) {
211    dli.dwLastError = GetLastError();
212    if(__pfnDliFailureHook2) pfnRet = (*__pfnDliFailureHook2)(dliFailGetProc,&dli);
213    if(!pfnRet) {
214      PDelayLoadInfo rgpdli[1] = { &dli};
215      RaiseException(VcppException(ERROR_SEVERITY_ERROR,ERROR_PROC_NOT_FOUND),0,1,(PULONG_PTR)(rgpdli));
216      pfnRet = dli.pfnCur;
217    }
218  }
219SetEntryHookBypass:
220  *ppfnIATEntry = pfnRet;
221HookBypass:
222  if(__pfnDliNotifyHook2) {
223    dli.dwLastError = 0;
224    dli.hmodCur = hmod;
225    dli.pfnCur = pfnRet;
226    (*__pfnDliNotifyHook2)(dliNoteEndProcessing,&dli);
227  }
228  return pfnRet;
229}
230
231WINBOOL WINAPI __FUnloadDelayLoadedDLL2(LPCSTR szDll)
232{
233  WINBOOL fRet = FALSE;
234  PUnloadInfo pui = __puiHead;
235
236  for(pui = __puiHead;pui;pui = pui->puiNext) {
237    LPCSTR szName = (LPCTSTR) PtrFromRVA(pui->pidd->rvaDLLName);
238    size_t cbName = __strlen(szName);
239    if(cbName==__strlen(szDll) && __memcmp(szDll,szName,cbName)==0) break;
240  }
241  if(pui && pui->pidd->rvaUnloadIAT) {
242    PCImgDelayDescr pidd = pui->pidd;
243    HMODULE *phmod = (HMODULE *) PtrFromRVA(pidd->rvaHmod);
244    HMODULE hmod = *phmod;
245    OverlayIAT((PImgThunkData) PtrFromRVA(pidd->rvaIAT), (PCImgThunkData) PtrFromRVA(pidd->rvaUnloadIAT));
246    FreeLibrary(hmod);
247    *phmod = NULL;
248    del_ULI((UnloadInfo *) pui);
249    fRet = TRUE;
250  }
251  return fRet;
252}
253
254HRESULT WINAPI __HrLoadAllImportsForDll(LPCSTR szDll)
255{
256  HRESULT hrRet = HRESULT_FROM_WIN32(ERROR_MOD_NOT_FOUND);
257  PIMAGE_NT_HEADERS pinh = PinhFromImageBase((HMODULE) (&__ImageBase));
258  if(pinh->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT].Size) {
259    PCImgDelayDescr pidd;
260    pidd = (PCImgDelayDescr) PtrFromRVA(pinh->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT].VirtualAddress);
261    while(pidd->rvaDLLName) {
262      LPCSTR szDllCur = (LPCSTR) PtrFromRVA(pidd->rvaDLLName);
263      size_t cchDllCur = __strlen(szDllCur);
264      if(cchDllCur==__strlen(szDll) && __memcmp(szDll,szDllCur,cchDllCur)==0) break;
265      pidd++;
266    }
267    if(pidd->rvaDLLName) {
268      FARPROC *ppfnIATEntry = (FARPROC *) PtrFromRVA(pidd->rvaIAT);
269      size_t cpfnIATEntries = CountOfImports((PCImgThunkData) (ppfnIATEntry));
270      FARPROC *ppfnIATEntryMax = ppfnIATEntry + cpfnIATEntries;
271      for(;ppfnIATEntry < ppfnIATEntryMax;ppfnIATEntry++) {
272        __delayLoadHelper2(pidd,ppfnIATEntry);
273      }
274      hrRet = S_OK;
275    }
276  }
277  return hrRet;
278}