Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

463 lines
12 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1997.
  5. //
  6. // File: D L O A D . C P P
  7. //
  8. // Contents: Delay Load Failure Hook
  9. //
  10. // Notes: This DLL implements a form of exception handler (a failure
  11. // hook, really) that is called by the delay-load section of
  12. // the loader. This DLL implements delay-load handlers for
  13. // standard APIs by returning an error code specific to the
  14. // API that failed to load. This allows clients of those APIs
  15. // to safely delay load the DLLs that implement those APIs
  16. // without having to worry about the success or failure of the
  17. // delay load operation. Failures in the delay load operation
  18. // cause the appropriate stub (implemented in this DLL) to be
  19. // invoked which simply returns an error code specific to the
  20. // API being called. (Other interface semantics such as
  21. // setting output parameters are also performed.)
  22. //
  23. // To Use: 1. Add the following line to one of your source modules.
  24. //
  25. // PfnDliHook __pfnDliFailureHook = DelayLoadFailureHook;
  26. //
  27. // 2. Define a global variable like the following:
  28. //
  29. // HANDLE g_hBaseDllHandle;
  30. //
  31. // And set it equal to your Dlls instance handle from
  32. // DLL_PROCESS_ATTACH of DllMain.
  33. //
  34. // Author: shaunco 19 May 1998
  35. //
  36. // Revised by: pritobla 23 Novemver 1998 (removed C-Runtime calls/RtlAssert
  37. // and modified the "To Use" section)
  38. //
  39. //----------------------------------------------------------------------------
  40. #include "precomp.h"
  41. #pragma hdrstop
  42. #if DBG
  43. VOID
  44. WINAPI
  45. AssertDelayLoadFailureMapsAreSorted (
  46. VOID
  47. )
  48. {
  49. const DLOAD_DLL_ENTRY* pDll;
  50. const DLOAD_PROCNAME_MAP* pProcNameMap;
  51. const DLOAD_ORDINAL_MAP* pOrdinalMap;
  52. CHAR szMsg[1024];
  53. UINT iDll, iProcName, iOrdinal;
  54. INT nRet;
  55. for (iDll = 0; iDll < g_DllMap.NumberOfEntries; iDll++)
  56. {
  57. if (iDll >= 1)
  58. {
  59. nRet = StrCmpIA (
  60. g_DllMap.pDllEntry[iDll].pszDll,
  61. g_DllMap.pDllEntry[iDll-1].pszDll);
  62. if (nRet <= 0)
  63. {
  64. wnsprintfA(szMsg, countof(szMsg),
  65. "dload: rows %u and %u are out of order in dload!g_DllMap",
  66. iDll-1, iDll);
  67. AssertFailedA(__FILE__, __LINE__, szMsg, TRUE);
  68. }
  69. }
  70. pDll = g_DllMap.pDllEntry + iDll;
  71. pProcNameMap = pDll->pProcNameMap;
  72. pOrdinalMap = pDll->pOrdinalMap;
  73. if (pProcNameMap)
  74. {
  75. ASSERT (pProcNameMap->NumberOfEntries);
  76. for (iProcName = 0;
  77. iProcName < pProcNameMap->NumberOfEntries;
  78. iProcName++)
  79. {
  80. if (iProcName >= 1)
  81. {
  82. nRet = StrCmpA (
  83. pProcNameMap->pProcNameEntry[iProcName].pszProcName,
  84. pProcNameMap->pProcNameEntry[iProcName-1].pszProcName);
  85. if (nRet <= 0)
  86. {
  87. wnsprintfA(szMsg, countof(szMsg),
  88. "dload: rows %u and %u of pProcNameMap are out "
  89. "of order in dload!g_DllMap for pszDll=%s",
  90. iProcName-1, iProcName, pDll->pszDll);
  91. AssertFailedA (__FILE__, __LINE__, szMsg, TRUE);
  92. }
  93. }
  94. }
  95. }
  96. if (pOrdinalMap)
  97. {
  98. ASSERT (pOrdinalMap->NumberOfEntries);
  99. for (iOrdinal = 0;
  100. iOrdinal < pOrdinalMap->NumberOfEntries;
  101. iOrdinal++)
  102. {
  103. if (iOrdinal >= 1)
  104. {
  105. if (pOrdinalMap->pOrdinalEntry[iOrdinal].dwOrdinal <=
  106. pOrdinalMap->pOrdinalEntry[iOrdinal-1].dwOrdinal)
  107. {
  108. wnsprintfA(szMsg, countof(szMsg),
  109. "dload: rows %u and %u of pOrdinalMap are out "
  110. "of order in dload!g_DllMap for pszDll=%s",
  111. iOrdinal-1, iOrdinal, pDll->pszDll);
  112. AssertFailedA(__FILE__, __LINE__, szMsg, TRUE);
  113. }
  114. }
  115. }
  116. }
  117. }
  118. }
  119. #endif // DBG
  120. const DLOAD_DLL_ENTRY*
  121. FindDll (
  122. LPCSTR pszDll
  123. )
  124. {
  125. const DLOAD_DLL_ENTRY* pDll = NULL;
  126. INT nResult;
  127. // These must be signed integers for the following binary search
  128. // to work correctly when iMiddle == 0 and nResult < 0.
  129. //
  130. INT iLow;
  131. INT iMiddle;
  132. INT iHigh;
  133. ASSERT(pszDll);
  134. ASSERT(StrLenA(pszDll) <= MAX_PATH);
  135. iLow = 0;
  136. iHigh = g_DllMap.NumberOfEntries - 1;
  137. while (iHigh >= iLow)
  138. {
  139. iMiddle = (iLow + iHigh) / 2;
  140. nResult = StrCmpIA (pszDll, g_DllMap.pDllEntry[iMiddle].pszDll);
  141. if (nResult < 0)
  142. {
  143. iHigh = iMiddle - 1;
  144. }
  145. else if (nResult > 0)
  146. {
  147. iLow = iMiddle + 1;
  148. }
  149. else
  150. {
  151. ASSERT (0 == nResult);
  152. pDll = &g_DllMap.pDllEntry[iMiddle];
  153. break;
  154. }
  155. }
  156. return pDll;
  157. }
  158. FARPROC
  159. LookupHandlerByName (
  160. LPCSTR pszProcName,
  161. const DLOAD_PROCNAME_MAP* pMap
  162. )
  163. {
  164. FARPROC pfnHandler = NULL;
  165. INT nResult;
  166. // These must be signed integers for the following binary search
  167. // to work correctly when iMiddle == 0 and nResult < 0.
  168. //
  169. INT iLow;
  170. INT iMiddle;
  171. INT iHigh;
  172. ASSERT (pszProcName);
  173. iLow = 0;
  174. iHigh = pMap->NumberOfEntries - 1;
  175. while (iHigh >= iLow)
  176. {
  177. iMiddle = (iLow + iHigh) / 2;
  178. nResult = StrCmpA (
  179. pszProcName,
  180. pMap->pProcNameEntry[iMiddle].pszProcName);
  181. if (nResult < 0)
  182. {
  183. iHigh = iMiddle - 1;
  184. }
  185. else if (nResult > 0)
  186. {
  187. iLow = iMiddle + 1;
  188. }
  189. else
  190. {
  191. ASSERT (0 == nResult);
  192. pfnHandler = pMap->pProcNameEntry[iMiddle].pfnProc;
  193. break;
  194. }
  195. }
  196. return pfnHandler;
  197. }
  198. FARPROC
  199. LookupHandlerByOrdinal (
  200. DWORD dwOrdinal,
  201. const DLOAD_ORDINAL_MAP* pMap
  202. )
  203. {
  204. FARPROC pfnHandler = NULL;
  205. DWORD dwOrdinalProbe;
  206. // These must be signed integers for the following binary search
  207. // to work correctly when iMiddle == 0 and dwOrdinal < dwOrdinalProbe.
  208. //
  209. INT iLow;
  210. INT iMiddle;
  211. INT iHigh;
  212. iLow = 0;
  213. iHigh = pMap->NumberOfEntries - 1;
  214. while (iHigh >= iLow)
  215. {
  216. iMiddle = (iLow + iHigh) / 2;
  217. dwOrdinalProbe = pMap->pOrdinalEntry[iMiddle].dwOrdinal;
  218. if (dwOrdinal < dwOrdinalProbe)
  219. {
  220. iHigh = iMiddle - 1;
  221. }
  222. else if (dwOrdinal > dwOrdinalProbe)
  223. {
  224. iLow = iMiddle + 1;
  225. }
  226. else
  227. {
  228. ASSERT (dwOrdinal == dwOrdinalProbe);
  229. pfnHandler = pMap->pOrdinalEntry[iMiddle].pfnProc;
  230. break;
  231. }
  232. }
  233. return pfnHandler;
  234. }
  235. FARPROC
  236. LookupHandler (
  237. PDelayLoadInfo pDelayInfo
  238. )
  239. {
  240. FARPROC pfnHandler = NULL;
  241. const DLOAD_DLL_ENTRY* pDll;
  242. ASSERT (pDelayInfo);
  243. #if DBG
  244. AssertDelayLoadFailureMapsAreSorted();
  245. #endif
  246. // Find the DLL record if we have one.
  247. //
  248. pDll = FindDll (pDelayInfo->szDll);
  249. if (pDll)
  250. {
  251. // Now find the handler whether it be by name or ordinal.
  252. //
  253. if (pDelayInfo->dlp.fImportByName &&
  254. pDll->pProcNameMap)
  255. {
  256. pfnHandler = LookupHandlerByName (
  257. pDelayInfo->dlp.szProcName,
  258. pDll->pProcNameMap);
  259. }
  260. else if (pDll->pOrdinalMap)
  261. {
  262. pfnHandler = LookupHandlerByOrdinal (
  263. pDelayInfo->dlp.dwOrdinal,
  264. pDll->pOrdinalMap);
  265. }
  266. }
  267. return pfnHandler;
  268. }
  269. #if DBG
  270. #define DBG_ERROR 0
  271. #define DBG_INFO 1
  272. //+---------------------------------------------------------------------------
  273. // Trace a message to the debug console. Prefix with who we are so
  274. // people know who to contact.
  275. //
  276. INT
  277. __cdecl
  278. DbgTrace (
  279. INT nLevel,
  280. PCSTR Format,
  281. ...
  282. )
  283. {
  284. INT cch = 0;
  285. if (nLevel >= DBG_INFO)
  286. {
  287. CHAR szBuf [1024];
  288. va_list argptr;
  289. va_start(argptr, Format);
  290. cch = wvnsprintfA(szBuf, countof(szBuf), Format, argptr);
  291. va_end(argptr);
  292. OutputDebugStringA("dload: ");
  293. OutputDebugStringA(szBuf);
  294. }
  295. return cch;
  296. }
  297. #endif // DBG
  298. //+---------------------------------------------------------------------------
  299. //
  300. //
  301. FARPROC
  302. WINAPI
  303. DelayLoadFailureHook (
  304. UINT unReason,
  305. PDelayLoadInfo pDelayInfo
  306. )
  307. {
  308. FARPROC ReturnValue = NULL;
  309. // According to the docs, this parameter is always supplied.
  310. //
  311. ASSERT (pDelayInfo);
  312. // Trace some potentially useful information about why we were called.
  313. //
  314. #if DBG
  315. if (pDelayInfo->dlp.fImportByName)
  316. {
  317. DbgTrace (DBG_INFO,
  318. "%s: Dll=%s, ProcName=%s\r\n",
  319. (dliFailLoadLib == unReason) ? "FailLoadLib" : "FailGetProc",
  320. pDelayInfo->szDll,
  321. pDelayInfo->dlp.szProcName);
  322. }
  323. else
  324. {
  325. DbgTrace (DBG_INFO,
  326. "%s: Dll=%s, Ordinal=%u\r\n",
  327. (dliFailLoadLib == unReason) ? "FailLoadLib" : "FailGetProc",
  328. pDelayInfo->szDll,
  329. pDelayInfo->dlp.dwOrdinal);
  330. }
  331. #endif
  332. // For a failed LoadLibrary, we will return the HINSTANCE of this DLL.
  333. // This will cause the loader to try a GetProcAddress on our DLL for the
  334. // function. This will subsequently fail and then we will be called
  335. // for dliFailGetProc below.
  336. //
  337. if (dliFailLoadLib == unReason)
  338. {
  339. ReturnValue = (FARPROC)g_hBaseDllHandle;
  340. }
  341. // The loader is asking us to return a pointer to a procedure.
  342. // Lookup the handler for this DLL/procedure and, if found, return it.
  343. // If we don't find it, we'll assert with a message about the missing
  344. // handler.
  345. //
  346. else if (dliFailGetProc == unReason)
  347. {
  348. FARPROC pfnHandler;
  349. // Try to find an error handler for the DLL/procedure.
  350. //
  351. pfnHandler = LookupHandler (pDelayInfo);
  352. if (pfnHandler)
  353. {
  354. #if DBG
  355. DbgTrace (DBG_INFO,
  356. "Returning handler function at address 0x%08x\r\n",
  357. (LONG_PTR)pfnHandler);
  358. #endif
  359. // Do this on behalf of the handler now that it is about to
  360. // be called.
  361. //
  362. SetLastError (ERROR_MOD_NOT_FOUND);
  363. }
  364. #if DBG
  365. else
  366. {
  367. CHAR szMsg[MAX_PATH];
  368. if (pDelayInfo->dlp.fImportByName)
  369. {
  370. wnsprintfA(szMsg, countof(szMsg),
  371. "No delayload handler found for Dll=%s, ProcName=%s\r\n",
  372. pDelayInfo->szDll,
  373. pDelayInfo->dlp.szProcName);
  374. }
  375. else
  376. {
  377. wnsprintfA(szMsg, countof(szMsg),
  378. "No delayload handler found for Dll=%s, Ordinal=%u\r\n",
  379. pDelayInfo->szDll,
  380. pDelayInfo->dlp.dwOrdinal);
  381. }
  382. AssertFailedA(__FILE__, __LINE__, szMsg, TRUE);
  383. }
  384. #endif
  385. ReturnValue = pfnHandler;
  386. }
  387. #if DBG
  388. else
  389. {
  390. ASSERT (NULL == ReturnValue);
  391. DbgTrace (DBG_INFO,
  392. "Unknown unReason (%u) passed to DelayLoadFailureHook. Ignoring.\r\n",
  393. unReason);
  394. }
  395. #endif
  396. return ReturnValue;
  397. }