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}