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.

2366 lines
58 KiB

  1. /*++
  2. Module Name:
  3. inetdbg.cxx
  4. Abstract:
  5. Debugging functions for internet DLL
  6. Author:
  7. Venkatraman Kudallur (venkatk)
  8. ( Ripped off from wininet )
  9. Revision History:
  10. 3-10-2000 venkatk
  11. Created
  12. --*/
  13. // !!!!!!!!!!!!!!!!!!!!!!!!!!!
  14. /* Exchanging the order of these 2 gives following error:
  15. Linking Executable - dll\daytona\objd\i386\urlmon.dll for i386
  16. dll\daytona\utils.lib(inetdbg.obj) : error LNK2001: unresolved external
  17. symbol "
  18. int __cdecl _sprintf(char *,char *,char *)" (?_sprintf@@YAHPAD00@Z)
  19. dll\daytona\objd\i386\urlmon.dll() : error LNK1120: 1 unresolved externals
  20. dll\daytona\binplace() : error BNP0000: Unable to place file objd\i386\urlmon.
  21. dll - exiting.
  22. */
  23. // !!!!!!!!!!!!!!!!!!!!!!!!!! Why?
  24. #include <urlint.h>
  25. #include "rprintf.h"
  26. #include "registry.h"
  27. #include "tls.h"
  28. #include <imagehlp.h>
  29. #include <wininet.h> //only for InternetVersionInfo!
  30. #include <ieverp.h> //for version strings
  31. #ifdef ENABLE_DEBUG
  32. //from macros.h
  33. #define PRIVATE
  34. #define PUBLIC
  35. //from util.cxx
  36. DWORD
  37. GetTickCountWrap()
  38. {
  39. #ifdef DEBUG_GETTICKCOUNT
  40. static BOOL fInit = FALSE;
  41. static DWORD dwDelta = 0;
  42. static DWORD dwBasis = 0;
  43. if (!fInit)
  44. {
  45. HKEY clientKey;
  46. if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  47. TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings"),
  48. 0, // reserved
  49. KEY_QUERY_VALUE,
  50. &clientKey))
  51. {
  52. DWORD dwSize = sizeof(dwDelta);
  53. RegQueryValueEx(clientKey, "RollOverDelta", NULL, NULL, (LPBYTE)&dwDelta, &dwSize);
  54. }
  55. dwBasis = GetTickCount();
  56. fInit = TRUE;
  57. }
  58. DWORD dwResult = GetTickCount() - dwBasis + dwDelta;
  59. return dwResult;
  60. #else
  61. return GetTickCount();
  62. #endif
  63. }
  64. //forward declaration
  65. BOOL
  66. InternetDebugGetLocalTime(
  67. OUT SYSTEMTIME * pstLocalTime,
  68. OUT DWORD * pdwMicroSec
  69. );
  70. //from debugmem.h
  71. #if defined(USE_DEBUG_MEMORY)
  72. //no debugmem capabilities yet.
  73. #define ALLOCATOR(Flags, Size) \
  74. LocalAlloc(Flags, Size)
  75. #define DEALLOCATOR(hLocal) \
  76. LocalFree(hLocal)
  77. #else //Retail
  78. #if USE_PRIVATE_HEAP_IN_RETAIL
  79. #error no other memory allocation schemes defined
  80. #else
  81. #ifndef WININET_UNIX_PRVATE_ALLOCATOR
  82. #define ALLOCATOR(Flags, Size) \
  83. LocalAlloc(Flags, Size)
  84. #define DEALLOCATOR(hLocal) \
  85. LocalFree(hLocal)
  86. #else
  87. HLOCAL IEUnixLocalAlloc(UINT wFlags, UINT wBytes);
  88. HLOCAL IEUnixLocalFree(HLOCAL hMem);
  89. #define ALLOCATOR(Flags, Size)\
  90. IEUnixLocalAlloc(Flags, Size)
  91. #define DEALLOCATOR(hLocal)\
  92. IEUnixLocalFree(hLocal)
  93. #endif //WININET_UNIX_PRVATE_ALLOCATOR
  94. #endif //USE_PRIVATE_HEAP_IN_RETAIL
  95. #endif //defined(USE_DEBUG_MEMORY)
  96. //from debugmem.h
  97. #define ALLOCATE_ZERO_MEMORY(Size) \
  98. ALLOCATE_MEMORY(LPTR, (Size))
  99. #define ALLOCATE_MEMORY(Flags, Size) \
  100. ALLOCATOR((UINT)(Flags), (UINT)(Size))
  101. #define FREE_MEMORY(hLocal) \
  102. DEALLOCATOR((HLOCAL)(hLocal))
  103. //from macros.h
  104. #define NEW(object) \
  105. (object FAR *)ALLOCATE_ZERO_MEMORY(sizeof(object))
  106. #define DEL(object) \
  107. FREE_MEMORY(object)
  108. //from Nttypes.h
  109. #define ARGUMENT_PRESENT(ArgumentPointer) (\
  110. (CHAR *)(ArgumentPointer) != (CHAR *)(NULL) )
  111. #define INTERNET_SETTINGS_KEY "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Internet Settings"
  112. //from globals.cxx
  113. #if !defined(VER_PRODUCTBUILD)
  114. #define VER_PRODUCTBUILD 0
  115. #endif
  116. PRIVATE DWORD InternetBuildNumber = VER_PRODUCTBUILD;
  117. #if !defined(VER_PRODUCTVERSION_STRING)
  118. #define VER_PRODUCTVERSION_STRING " "
  119. #endif
  120. #if !defined(URLMON_MAJOR_VERSION)
  121. #define URLMON_MAJOR_VERSION 1
  122. #endif
  123. #if !defined(URLMON_MINOR_VERSION)
  124. #define URLMON_MINOR_VERSION 2
  125. #endif
  126. PRIVATE INTERNET_VERSION_INFO InternetVersionInfo = {
  127. URLMON_MAJOR_VERSION,
  128. URLMON_MINOR_VERSION
  129. };
  130. #if 0
  131. #endif //0
  132. //
  133. // private manifests
  134. //
  135. #define SWITCH_VARIABLE_NAME "UrlmonDebugging"
  136. #define CONTROL_VARIABLE_NAME "UrlmonControl"
  137. #define CATEGORY_VARIABLE_NAME "UrlmonCategory"
  138. #define ERROR_VARIABLE_NAME "UrlmonError"
  139. #define BREAK_VARIABLE_NAME "UrlmonBreak"
  140. #define DEFAULT_LOG_VARIABLE_NAME "UrlmonLog"
  141. #define CHECK_LIST_VARIABLE_NAME "UrlmonCheckSerializedList"
  142. #define LOG_FILE_VARIABLE_NAME "UrlmonLogFile"
  143. #define INDENT_VARIABLE_NAME "UrlmonLogIndent"
  144. #define NO_PID_IN_LOG_FILENAME "UrlmonNoPidInLogFilename"
  145. #define NO_EXCEPTION_HANDLER "UrlmonNoExceptionHandler"
  146. #define DEFAULT_LOG_FILE_NAME "URLMON.LOG"
  147. #define ENVIRONMENT_VARIABLE_BUFFER_LENGTH 80
  148. #define PRINTF_STACK_BUFFER_LENGTH 4096
  149. //
  150. // private macros
  151. //
  152. #define CASE_OF(constant) case constant: return # constant
  153. //
  154. // private prototypes
  155. //
  156. PRIVATE
  157. VOID
  158. InternetDebugPrintString(
  159. IN LPSTR String
  160. );
  161. PRIVATE
  162. VOID
  163. InternetGetDebugVariableString(
  164. IN LPSTR lpszVariableName,
  165. OUT LPSTR lpszVariable,
  166. IN DWORD dwVariableLen
  167. );
  168. PRIVATE
  169. LPSTR
  170. ExtractFileName(
  171. IN LPSTR Module,
  172. OUT LPSTR Buf
  173. );
  174. PRIVATE
  175. LPSTR
  176. SetDebugPrefix(
  177. IN LPSTR Buffer
  178. );
  179. //
  180. //
  181. // these variables are employed in macros, so must be public
  182. //
  183. PUBLIC DWORD InternetDebugErrorLevel = DBG_ERROR;
  184. PUBLIC DWORD InternetDebugControlFlags = DBG_NO_DEBUG;
  185. PUBLIC DWORD InternetDebugCategoryFlags = 0;
  186. PUBLIC DWORD InternetDebugBreakFlags = 0;
  187. //
  188. // these variables are only accessed in this module, so can be private
  189. //
  190. PRIVATE int InternetDebugIndentIncrement = 2;
  191. PRIVATE HANDLE InternetDebugFileHandle = INVALID_HANDLE_VALUE;
  192. PRIVATE char InternetDebugFilename[MAX_PATH + 1] = DEFAULT_LOG_FILE_NAME;
  193. PRIVATE BOOL InternetDebugEnabled = TRUE;
  194. PRIVATE DWORD InternetDebugStartTime = 0;
  195. extern "C" {
  196. #if defined(UNIX) && defined(ux10)
  197. /* Temporary fix for Apogee Compiler bug on HP only */
  198. extern BOOL fCheckEntryOnList;
  199. #else
  200. BOOL fCheckEntryOnList;
  201. #endif /* UNIX */
  202. }
  203. //
  204. // high frequency performance counter globals
  205. //
  206. PRIVATE LONGLONG ftInit; // initial local time
  207. PRIVATE LONGLONG pcInit; // initial perf counter
  208. PRIVATE LONGLONG pcFreq; // perf counter frequency
  209. //
  210. // functions
  211. //
  212. VOID
  213. InternetDebugInitialize(
  214. VOID
  215. )
  216. /*++
  217. Routine Description:
  218. reads environment INETDBG flags and opens debug log file if required
  219. Arguments:
  220. None.
  221. Return Value:
  222. None.
  223. --*/
  224. {
  225. //
  226. // ensure registry key open
  227. //
  228. OpenInternetSettingsKey();
  229. //
  230. // record the starting tick count for cumulative deltas
  231. //
  232. InternetDebugStartTime = GetTickCountWrap();
  233. if (QueryPerformanceFrequency ((LARGE_INTEGER *) &pcFreq) && pcFreq) {
  234. QueryPerformanceCounter ((LARGE_INTEGER *) &pcInit);
  235. SYSTEMTIME st;
  236. GetLocalTime (&st);
  237. SystemTimeToFileTime (&st, (FILETIME *) &ftInit);
  238. }
  239. // check see if there are any debug variable overrides in the environment
  240. // or the registry. If "UrlmonLog=<!0>" is set then we use the flags that
  241. // are most commonly used to generate URLMON.LOG, with no console or
  242. // debugger output. We allow the other variables to be overridden
  243. //
  244. BOOL defaultDebugVariables = FALSE;
  245. InternetGetDebugVariable(DEFAULT_LOG_VARIABLE_NAME, (LPDWORD)&defaultDebugVariables);
  246. if (defaultDebugVariables) {
  247. InternetDebugEnabled = TRUE;
  248. InternetDebugControlFlags = INTERNET_DEBUG_CONTROL_DEFAULT;
  249. InternetDebugCategoryFlags = INTERNET_DEBUG_CATEGORY_DEFAULT;
  250. InternetDebugErrorLevel = INTERNET_DEBUG_ERROR_LEVEL_DEFAULT;
  251. InternetDebugBreakFlags = 0;
  252. }
  253. InternetGetDebugVariable(SWITCH_VARIABLE_NAME, (LPDWORD)&InternetDebugEnabled);
  254. InternetGetDebugVariable(CONTROL_VARIABLE_NAME, &InternetDebugControlFlags);
  255. InternetGetDebugVariable(CATEGORY_VARIABLE_NAME, &InternetDebugCategoryFlags);
  256. InternetGetDebugVariable(ERROR_VARIABLE_NAME, &InternetDebugErrorLevel);
  257. InternetGetDebugVariable(BREAK_VARIABLE_NAME, &InternetDebugBreakFlags);
  258. InternetGetDebugVariable(CHECK_LIST_VARIABLE_NAME, (LPDWORD)&fCheckEntryOnList);
  259. InternetGetDebugVariable(INDENT_VARIABLE_NAME, (LPDWORD)&InternetDebugIndentIncrement);
  260. InternetGetDebugVariableString(LOG_FILE_VARIABLE_NAME,
  261. InternetDebugFilename,
  262. sizeof(InternetDebugFilename)
  263. );
  264. DWORD InternetNoPidInLogFilename=0;
  265. InternetGetDebugVariable(NO_PID_IN_LOG_FILENAME, &InternetNoPidInLogFilename);
  266. if (!InternetNoPidInLogFilename)
  267. {
  268. char szFullPathName[MAX_PATH + 1];
  269. LPSTR szExecutableName;
  270. if (GetModuleFileName(NULL, szFullPathName, sizeof(szFullPathName)))
  271. {
  272. szExecutableName = strrchr(szFullPathName, '\\');
  273. if (szExecutableName != NULL)
  274. ++szExecutableName;
  275. else
  276. szExecutableName = szFullPathName;
  277. }
  278. else
  279. szExecutableName = "";
  280. DWORD cbFilenameLen = strlen(InternetDebugFilename);
  281. // ".xxxxx.yyy.#########.LOG"
  282. DWORD cbProcessInfoLenMax = 1 + strlen(szExecutableName) + 1 + 9 + 1 + 3;
  283. if (cbProcessInfoLenMax < sizeof(InternetDebugFilename))
  284. wsprintf(InternetDebugFilename+cbFilenameLen, ".%s.%u.LOG",
  285. szExecutableName,
  286. GetCurrentProcessId());
  287. };
  288. if ((InternetDebugIndentIncrement < 0) || (InternetDebugIndentIncrement > 32)) {
  289. InternetDebugIndentIncrement = 2;
  290. }
  291. //
  292. // quit now if debugging is disabled
  293. //
  294. if (!InternetDebugEnabled) {
  295. InternetDebugControlFlags |= (DBG_NO_DEBUG | DBG_NO_DATA_DUMP);
  296. return;
  297. }
  298. //
  299. // if we want to write debug output to file, open URLMON.LOG in the current
  300. // directory. Open it in text mode, for write-only (by this process)
  301. //
  302. if (InternetDebugControlFlags & DBG_TO_FILE) {
  303. if (!InternetReopenDebugFile(InternetDebugFilename)) {
  304. InternetDebugControlFlags &= ~DBG_TO_FILE;
  305. }
  306. }
  307. }
  308. VOID
  309. InternetDebugTerminate(
  310. VOID
  311. )
  312. /*++
  313. Routine Description:
  314. Performs any required debug termination
  315. Arguments:
  316. None.
  317. Return Value:
  318. None.
  319. --*/
  320. {
  321. //moved into this function bcos we don't this only for debugging.
  322. CloseInternetSettingsKey();
  323. if (InternetDebugControlFlags & DBG_TO_FILE) {
  324. InternetCloseDebugFile();
  325. }
  326. InternetDebugControlFlags = DBG_NO_DEBUG;
  327. }
  328. BOOL
  329. InternetOpenDebugFile(
  330. VOID
  331. )
  332. /*++
  333. Routine Description:
  334. Opens debug filename if not already open. Use InternetDebugFilename
  335. Arguments:
  336. None.
  337. Return Value:
  338. BOOL
  339. TRUE - file was opened
  340. FALSE - file not opened (already open or error)
  341. --*/
  342. {
  343. if (InternetDebugFileHandle == INVALID_HANDLE_VALUE) {
  344. InternetDebugFileHandle = CreateFile(
  345. InternetDebugFilename,
  346. GENERIC_WRITE,
  347. FILE_SHARE_READ,
  348. NULL, // lpSecurityAttributes
  349. (InternetDebugControlFlags & DBG_APPEND_FILE)
  350. ? OPEN_ALWAYS
  351. : CREATE_ALWAYS,
  352. FILE_ATTRIBUTE_NORMAL
  353. | FILE_FLAG_SEQUENTIAL_SCAN
  354. | ((InternetDebugControlFlags & DBG_FLUSH_OUTPUT)
  355. ? FILE_FLAG_WRITE_THROUGH
  356. : 0),
  357. NULL
  358. );
  359. return InternetDebugFileHandle != INVALID_HANDLE_VALUE;
  360. }
  361. return FALSE;
  362. }
  363. BOOL
  364. InternetReopenDebugFile(
  365. IN LPSTR Filename
  366. )
  367. /*++
  368. Routine Description:
  369. (Re)opens a debug log file. Closes the current one if it is open
  370. Arguments:
  371. Filename - new file to open
  372. Return Value:
  373. None.
  374. --*/
  375. {
  376. if (InternetDebugFileHandle != INVALID_HANDLE_VALUE) {
  377. InternetCloseDebugFile();
  378. }
  379. if (Filename && *Filename) {
  380. InternetDebugFileHandle = CreateFile(
  381. Filename,
  382. GENERIC_WRITE,
  383. FILE_SHARE_READ,
  384. NULL, // lpSecurityAttributes
  385. (InternetDebugControlFlags & DBG_APPEND_FILE)
  386. ? OPEN_ALWAYS
  387. : CREATE_ALWAYS,
  388. FILE_ATTRIBUTE_NORMAL
  389. | FILE_FLAG_SEQUENTIAL_SCAN
  390. | ((InternetDebugControlFlags & DBG_FLUSH_OUTPUT)
  391. ? FILE_FLAG_WRITE_THROUGH
  392. : 0),
  393. NULL
  394. );
  395. //
  396. // put our start info in the log file. Mainly useful when we're
  397. // appending to the file
  398. //
  399. if (InternetDebugFileHandle != INVALID_HANDLE_VALUE) {
  400. SYSTEMTIME currentTime;
  401. char filespec[MAX_PATH + 1];
  402. LPSTR filename;
  403. if (GetModuleFileName(NULL, filespec, sizeof(filespec))) {
  404. filename = strrchr(filespec, '\\');
  405. if (filename != NULL) {
  406. ++filename;
  407. } else {
  408. filename = filespec;
  409. }
  410. } else {
  411. filename = "";
  412. }
  413. InternetDebugGetLocalTime(&currentTime, NULL);
  414. InternetDebugPrintf("\n"
  415. ">>>> Urlmon Version %d.%d Build %s.%d " __DATE__ " " __TIME__ "\n"
  416. ">>>> Process %s [%d (%#x)] started at %02d:%02d:%02d.%03d %02d/%02d/%d\n",
  417. InternetVersionInfo.dwMajorVersion,
  418. InternetVersionInfo.dwMinorVersion,
  419. VER_PRODUCTVERSION_STRING,
  420. InternetBuildNumber,
  421. filename,
  422. GetCurrentProcessId(),
  423. GetCurrentProcessId(),
  424. currentTime.wHour,
  425. currentTime.wMinute,
  426. currentTime.wSecond,
  427. currentTime.wMilliseconds,
  428. currentTime.wMonth,
  429. currentTime.wDay,
  430. currentTime.wYear
  431. );
  432. InternetDebugPrintf(">>>> Command line = %q\n", GetCommandLine());
  433. InternetDebugPrintf("\n"
  434. " InternetDebugErrorLevel = %s [%d]\n"
  435. " InternetDebugControlFlags = %#08x\n"
  436. " InternetDebugCategoryFlags = %#08x\n"
  437. " InternetDebugBreakFlags = %#08x\n"
  438. " InternetDebugIndentIncrement = %d\n"
  439. "\n",
  440. (InternetDebugErrorLevel == DBG_INFO) ? "Info"
  441. : (InternetDebugErrorLevel == DBG_WARNING) ? "Warning"
  442. : (InternetDebugErrorLevel == DBG_ERROR) ? "Error"
  443. : (InternetDebugErrorLevel == DBG_FATAL) ? "Fatal"
  444. : (InternetDebugErrorLevel == DBG_ALWAYS) ? "Always"
  445. : "?",
  446. InternetDebugErrorLevel,
  447. InternetDebugControlFlags,
  448. InternetDebugCategoryFlags,
  449. InternetDebugBreakFlags,
  450. InternetDebugIndentIncrement
  451. );
  452. return TRUE;
  453. }
  454. }
  455. return FALSE;
  456. }
  457. VOID
  458. InternetCloseDebugFile(
  459. VOID
  460. )
  461. /*++
  462. Routine Description:
  463. Closes the current debug log file
  464. Arguments:
  465. None.
  466. Return Value:
  467. None.
  468. --*/
  469. {
  470. if (InternetDebugFileHandle != INVALID_HANDLE_VALUE) {
  471. if (InternetDebugControlFlags & DBG_FLUSH_OUTPUT) {
  472. InternetFlushDebugFile();
  473. }
  474. CloseHandle(InternetDebugFileHandle);
  475. InternetDebugFileHandle = INVALID_HANDLE_VALUE;
  476. }
  477. }
  478. VOID
  479. InternetFlushDebugFile(
  480. VOID
  481. )
  482. /*++
  483. Routine Description:
  484. description-of-function.
  485. Arguments:
  486. None.
  487. Return Value:
  488. None.
  489. --*/
  490. {
  491. if (InternetDebugFileHandle != INVALID_HANDLE_VALUE) {
  492. FlushFileBuffers(InternetDebugFileHandle);
  493. }
  494. }
  495. VOID
  496. InternetDebugSetControlFlags(
  497. IN DWORD dwFlags
  498. )
  499. /*++
  500. Routine Description:
  501. Sets debug control flags
  502. Arguments:
  503. dwFlags - flags to set
  504. Return Value:
  505. None.
  506. --*/
  507. {
  508. InternetDebugControlFlags |= dwFlags;
  509. }
  510. VOID
  511. InternetDebugResetControlFlags(
  512. IN DWORD dwFlags
  513. )
  514. /*++
  515. Routine Description:
  516. Resets debug control flags
  517. Arguments:
  518. dwFlags - flags to reset
  519. Return Value:
  520. None.
  521. --*/
  522. {
  523. InternetDebugControlFlags &= ~dwFlags;
  524. }
  525. VOID
  526. InternetDebugEnter(
  527. IN DWORD Category,
  528. IN DEBUG_FUNCTION_RETURN_TYPE ReturnType,
  529. IN LPCSTR Function,
  530. IN LPCSTR ParameterList OPTIONAL,
  531. IN ...
  532. )
  533. /*++
  534. Routine Description:
  535. Creates an INTERNET_DEBUG_RECORD for the current function and adds it to
  536. the per-thread (debug) call-tree
  537. Arguments:
  538. Category - category flags, e.g. DBG_FTP
  539. ReturnType - type of data it returns
  540. Function - name of the function. Must be global, static string
  541. ParameterList - string describing parameters to function, or NULL if none
  542. ... - parameters to function
  543. Return Value:
  544. None.
  545. --*/
  546. {
  547. if (InternetDebugControlFlags & DBG_NO_DEBUG) {
  548. return;
  549. }
  550. HRESULT hr = S_OK;
  551. CUrlMkTls tls(hr); // hr passed by reference!
  552. if (FAILED(hr))
  553. return;
  554. LPDEBUG_URLMON_FUNC_RECORD pCurrentFunction;
  555. pCurrentFunction = NEW(DEBUG_URLMON_FUNC_RECORD);
  556. pCurrentFunction->Stack = tls->Stack;
  557. pCurrentFunction->Category = Category;
  558. pCurrentFunction->ReturnType = ReturnType;
  559. pCurrentFunction->Function = Function;
  560. pCurrentFunction->LastTime = GetTickCountWrap();
  561. tls->Stack = pCurrentFunction;
  562. ++tls->CallDepth;
  563. //
  564. // if the function's category (FTP, GOPHER, HTTP) is selected in the
  565. // category flags, then we dump the function entry information
  566. //
  567. if (InternetDebugCategoryFlags & Category) {
  568. char buf[4096];
  569. LPSTR bufptr;
  570. bufptr = buf;
  571. bufptr += rsprintf(bufptr, "%s(", Function);
  572. __try
  573. {
  574. if (ARGUMENT_PRESENT(ParameterList)) {
  575. va_list parms;
  576. va_start(parms, ParameterList);
  577. bufptr += _sprintf(bufptr, (char*)ParameterList, parms);
  578. va_end(parms);
  579. }
  580. rsprintf(bufptr, ")\n");
  581. }
  582. __except(EXCEPTION_EXECUTE_HANDLER)
  583. {
  584. if (((DWORD(bufptr-buf) < (sizeof("*********Exception occured!!\n")+1)))
  585. && (bufptr>buf))
  586. wsprintf(bufptr, "*********Exception occured!!\n");
  587. else
  588. wsprintf(buf, "*********Exception occured!!\n");
  589. }
  590. InternetDebugPrintString(buf);
  591. //
  592. // only increase the indentation if we will display debug information
  593. // for this category
  594. //
  595. tls->IndentIncrement += InternetDebugIndentIncrement;
  596. }
  597. }
  598. VOID
  599. InternetDebugLeave(
  600. IN DWORD_PTR Variable,
  601. IN LPCSTR Filename,
  602. IN DWORD LineNumber
  603. )
  604. /*++
  605. Routine Description:
  606. Destroys the INTERNET_DEBUG_RECORD for the current function and dumps info
  607. about what the function is returning, if requested to do so
  608. Arguments:
  609. Variable - variable containing value being returned by function
  610. Filename - name of file where DEBUG_LEAVE() invoked
  611. LineNumber - and line number in Filename
  612. Return Value:
  613. None.
  614. --*/
  615. {
  616. LPSTR format;
  617. LPSTR errstr;
  618. BOOL noVar;
  619. char formatBuf[128];
  620. DWORD lastError;
  621. char hexnumBuf[15];
  622. if (InternetDebugControlFlags & DBG_NO_DEBUG) {
  623. return;
  624. }
  625. //
  626. // seems that something in this path can nuke the last error, so we must
  627. // refresh it
  628. //
  629. lastError = GetLastError();
  630. HRESULT hr = S_OK;
  631. CUrlMkTls tls(hr); // hr passed by reference!
  632. if (FAILED(hr))
  633. return;
  634. LPDEBUG_URLMON_FUNC_RECORD pCurrentFunction = tls->Stack;
  635. if (!pCurrentFunction) {
  636. return;
  637. }
  638. //
  639. // we are about to output a diagnostic message to the debug log, debugger,
  640. // or console. First check that we are required to display messages at
  641. // this level. The level for function ENTER and LEAVE is INFO
  642. //
  643. {
  644. //
  645. // only display the string and reduce the indent if we are requested
  646. // for information about this category
  647. //
  648. errstr = NULL;
  649. noVar = FALSE;
  650. if (InternetDebugCategoryFlags & pCurrentFunction->Category) {
  651. switch (pCurrentFunction->ReturnType) {
  652. case None:
  653. format = "%s() returning VOID";
  654. noVar = TRUE;
  655. break;
  656. case Bool:
  657. Variable = (DWORD_PTR)(Variable ? "TRUE" : "FALSE");
  658. //
  659. // *** FALL THROUGH ***
  660. //
  661. case String:
  662. format = "%s() returning %s";
  663. break;
  664. case Int:
  665. format = "%s() returning %d";
  666. break;
  667. case Dword:
  668. format = "%s() returning %u";
  669. break;
  670. case Hresult:
  671. format = "%s() returning %u";
  672. errstr = InternetMapError((DWORD)Variable);
  673. if (errstr != NULL) {
  674. if (*errstr == '?') {
  675. rsprintf(hexnumBuf, "%#x", Variable);
  676. errstr = hexnumBuf;
  677. format = "%s() returning %u [?] (%s)";
  678. } else {
  679. format = "%s() returning %u [%s]";
  680. }
  681. }
  682. break;
  683. case Handle:
  684. case Pointer:
  685. if (Variable == 0) {
  686. format = "%s() returning NULL";
  687. noVar = TRUE;
  688. } else {
  689. if (pCurrentFunction->ReturnType == Handle) {
  690. format = "%s() returning handle %#x";
  691. } else {
  692. format = "%s() returning %#x";
  693. }
  694. }
  695. break;
  696. default:
  697. INET_ASSERT(FALSE);
  698. break;
  699. }
  700. tls->IndentIncrement -= InternetDebugIndentIncrement;
  701. if (tls->IndentIncrement < 0) {
  702. tls->IndentIncrement = 0;
  703. }
  704. //
  705. // add line number info, if requested
  706. //
  707. strcpy(formatBuf, format);
  708. if (!(InternetDebugControlFlags & DBG_NO_LINE_NUMBER)) {
  709. strcat(formatBuf, " (line %d)");
  710. }
  711. strcat(formatBuf, "\n");
  712. //
  713. // output an empty line if we are required to separate API calls in
  714. // the log. Only do this if this is an API level function, and it
  715. // is the top-level function
  716. //
  717. if ((InternetDebugControlFlags & DBG_SEPARATE_APIS)
  718. && (pCurrentFunction->Stack == NULL)) {
  719. strcat(formatBuf, "\n");
  720. }
  721. //
  722. // dump the line, depending on requirements and number of arguments
  723. //
  724. if (noVar) {
  725. InternetDebugPrint(formatBuf,
  726. pCurrentFunction->Function,
  727. LineNumber
  728. );
  729. } else if (errstr != NULL) {
  730. InternetDebugPrint(formatBuf,
  731. pCurrentFunction->Function,
  732. Variable,
  733. errstr,
  734. LineNumber
  735. );
  736. } else {
  737. InternetDebugPrint(formatBuf,
  738. pCurrentFunction->Function,
  739. Variable,
  740. LineNumber
  741. );
  742. }
  743. /*
  744. //
  745. // output an empty line if we are required to separate API calls in
  746. // the log. Only do this if this is an API level function, and it
  747. // is the top-level function
  748. //
  749. if ((InternetDebugControlFlags & DBG_SEPARATE_APIS)
  750. && (pCurrentFunction->Stack == NULL)) {
  751. //
  752. // don't call InternetDebugPrint - we don't need timing, thread,
  753. // level etc. information just for the separator
  754. //
  755. InternetDebugOut("\n", FALSE);
  756. }
  757. */
  758. }
  759. }
  760. //
  761. // regardless of whether we are outputting debug info for this category,
  762. // remove the debug record and reduce the call-depth
  763. //
  764. --tls->CallDepth;
  765. tls->Stack = pCurrentFunction->Stack;
  766. DEL(pCurrentFunction);
  767. //
  768. // refresh the last error, in case it was nuked
  769. //
  770. SetLastError(lastError);
  771. }
  772. VOID
  773. InternetDebugError(
  774. IN DWORD Error
  775. )
  776. /*++
  777. Routine Description:
  778. Used to display that a function is returning an error. We try to display a
  779. symbolic name for the error too (as when we are returning a DWORD from a
  780. function, using DEBUG_LEAVE)
  781. Displays a string of the form:
  782. Foo() returning error 87 [ERROR_INVALID_PARAMETER]
  783. Arguments:
  784. Error - the error code
  785. Return Value:
  786. None.
  787. --*/
  788. {
  789. LPSTR errstr;
  790. DWORD lastError;
  791. char hexnumBuf[15];
  792. if (InternetDebugControlFlags & DBG_NO_DEBUG) {
  793. return;
  794. }
  795. //
  796. // seems that something in this path can nuke the last error, so we must
  797. // refresh it
  798. //
  799. lastError = GetLastError();
  800. HRESULT hr = S_OK;
  801. CUrlMkTls tls(hr); // hr passed by reference!
  802. if (FAILED(hr))
  803. return;
  804. LPDEBUG_URLMON_FUNC_RECORD pCurrentFunction = tls->Stack;
  805. if (pCurrentFunction == NULL) {
  806. return;
  807. }
  808. errstr = InternetMapError(Error);
  809. if ((errstr == NULL) || (*errstr == '?')) {
  810. rsprintf(hexnumBuf, "%#x", Error);
  811. errstr = hexnumBuf;
  812. }
  813. InternetDebugPrint("%s() returning %d [%s]\n",
  814. pCurrentFunction->Function,
  815. Error,
  816. errstr
  817. );
  818. //
  819. // refresh the last error, in case it was nuked
  820. //
  821. SetLastError(lastError);
  822. }
  823. VOID
  824. InternetDebugPrint(
  825. IN LPSTR Format,
  826. ...
  827. )
  828. /*++
  829. Routine Description:
  830. Internet equivalent of printf()
  831. Arguments:
  832. Format - printf format string
  833. ... - any extra args
  834. Return Value:
  835. None.
  836. --*/
  837. {
  838. if (InternetDebugControlFlags & DBG_NO_DEBUG) {
  839. return;
  840. }
  841. char buf[PRINTF_STACK_BUFFER_LENGTH];
  842. LPSTR bufptr;
  843. bufptr = SetDebugPrefix(buf);
  844. if (bufptr == NULL) {
  845. return;
  846. }
  847. //
  848. // now append the string that the DEBUG_PRINT originally gave us
  849. //
  850. va_list list;
  851. va_start(list, Format);
  852. _sprintf(bufptr, Format, list);
  853. va_end(list);
  854. InternetDebugOut(buf, FALSE);
  855. }
  856. VOID
  857. InternetDebugPrintValist(
  858. IN LPSTR Format,
  859. va_list list
  860. )
  861. /*++
  862. Routine Description:
  863. Internet equivalent of printf(), but takes valist as the args
  864. Arguments:
  865. Format - printf format string
  866. list - stack frame of variable arguments
  867. Return Value:
  868. None.
  869. --*/
  870. {
  871. if (InternetDebugControlFlags & DBG_NO_DEBUG) {
  872. return;
  873. }
  874. char buf[PRINTF_STACK_BUFFER_LENGTH];
  875. LPSTR bufptr;
  876. bufptr = SetDebugPrefix(buf);
  877. if (bufptr == NULL) {
  878. return;
  879. }
  880. _sprintf(bufptr, Format, list);
  881. InternetDebugOut(buf, FALSE);
  882. }
  883. PRIVATE
  884. VOID
  885. InternetDebugPrintString(
  886. IN LPSTR String
  887. )
  888. /*++
  889. Routine Description:
  890. Same as InternetDebugPrint(), except we perform no expansion on the string
  891. Arguments:
  892. String - already formatted string (may contain %s)
  893. Return Value:
  894. None.
  895. --*/
  896. {
  897. if (InternetDebugControlFlags & DBG_NO_DEBUG) {
  898. return;
  899. }
  900. char buf[PRINTF_STACK_BUFFER_LENGTH];
  901. LPSTR bufptr;
  902. bufptr = SetDebugPrefix(buf);
  903. if (bufptr == NULL) {
  904. return;
  905. }
  906. //
  907. // now append the string that the DEBUG_PRINT originally gave us
  908. //
  909. strcpy(bufptr, String);
  910. InternetDebugOut(buf, FALSE);
  911. }
  912. VOID
  913. InternetDebugPrintf(
  914. IN LPSTR Format,
  915. IN ...
  916. )
  917. /*++
  918. Routine Description:
  919. Same as InternetDebugPrint(), but we don't access the per-thread info
  920. (because we may not have any)
  921. Arguments:
  922. Format - printf format string
  923. ... - any extra args
  924. Return Value:
  925. None.
  926. --*/
  927. {
  928. if (InternetDebugControlFlags & DBG_NO_DEBUG) {
  929. return;
  930. }
  931. va_list list;
  932. char buf[PRINTF_STACK_BUFFER_LENGTH];
  933. va_start(list, Format);
  934. _sprintf(buf, Format, list);
  935. va_end(list);
  936. InternetDebugOut(buf, FALSE);
  937. }
  938. VOID
  939. InternetDebugOut(
  940. IN LPSTR Buffer,
  941. IN BOOL Assert
  942. )
  943. /*++
  944. Routine Description:
  945. Writes a string somewhere - to the debug log file, to the console, or via
  946. the debugger, or any combination
  947. Arguments:
  948. Buffer - pointer to formatted buffer to write
  949. Assert - TRUE if this function is being called from InternetAssert(), in
  950. which case we *always* write to the debugger. Of course, there
  951. may be no debugger attached, in which case no action is taken
  952. Return Value:
  953. None.
  954. --*/
  955. {
  956. int buflen;
  957. DWORD written;
  958. buflen = strlen(Buffer);
  959. if ((InternetDebugControlFlags & DBG_TO_FILE)
  960. && (InternetDebugFileHandle != INVALID_HANDLE_VALUE)) {
  961. WriteFile(InternetDebugFileHandle, Buffer, buflen, &written, NULL);
  962. if (InternetDebugControlFlags & DBG_FLUSH_OUTPUT) {
  963. InternetFlushDebugFile();
  964. }
  965. }
  966. if (InternetDebugControlFlags & DBG_TO_CONSOLE) {
  967. WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE),
  968. Buffer,
  969. buflen,
  970. &written,
  971. 0
  972. );
  973. }
  974. if (Assert || (InternetDebugControlFlags & DBG_TO_DEBUGGER)) {
  975. OutputDebugString(Buffer);
  976. }
  977. }
  978. VOID
  979. InternetDebugDump(
  980. IN LPSTR Text,
  981. IN LPBYTE Address,
  982. IN DWORD Size
  983. )
  984. /*++
  985. Routine Description:
  986. Dumps Size bytes at Address, in the time-honoured debug tradition
  987. Arguments:
  988. Text - to display before dumping data
  989. Address - start of buffer
  990. Size - number of bytes
  991. Return Value:
  992. None.
  993. --*/
  994. {
  995. //
  996. // if flags say no data dumps then quit
  997. //
  998. if (InternetDebugControlFlags & (DBG_NO_DEBUG | DBG_NO_DATA_DUMP)) {
  999. return;
  1000. }
  1001. //
  1002. // display the introduction text, if any
  1003. //
  1004. if (Text) {
  1005. if (InternetDebugControlFlags & DBG_INDENT_DUMP) {
  1006. InternetDebugPrint(Text);
  1007. } else {
  1008. InternetDebugOut(Text, FALSE);
  1009. }
  1010. }
  1011. char buf[128];
  1012. //
  1013. // display a line telling us how much data there is, if requested to
  1014. //
  1015. if (InternetDebugControlFlags & DBG_DUMP_LENGTH) {
  1016. rsprintf(buf, "%d (%#x) bytes @ %#x\n", Size, Size, Address);
  1017. if (InternetDebugControlFlags & DBG_INDENT_DUMP) {
  1018. InternetDebugPrintString(buf);
  1019. } else {
  1020. InternetDebugOut(buf, FALSE);
  1021. }
  1022. }
  1023. //
  1024. // dump out the data, debug style
  1025. //
  1026. while (Size) {
  1027. int len = InternetDebugDumpFormat(Address, Size, sizeof(BYTE), buf);
  1028. //
  1029. // if we are to indent the data to the current level, then display the
  1030. // buffer via InternetDebugPrint() which will apply all the thread id,
  1031. // indentation, and other options selected, else just display the data
  1032. // via InternetDebugOut(), which will simply send it to the output media
  1033. //
  1034. if (InternetDebugControlFlags & DBG_INDENT_DUMP) {
  1035. InternetDebugPrintString(buf);
  1036. } else {
  1037. InternetDebugOut(buf, FALSE);
  1038. }
  1039. Address += len;
  1040. Size -= len;
  1041. }
  1042. }
  1043. DWORD
  1044. InternetDebugDumpFormat(
  1045. IN LPBYTE Address,
  1046. IN DWORD Size,
  1047. IN DWORD ElementSize,
  1048. OUT LPSTR Buffer
  1049. )
  1050. /*++
  1051. Routine Description:
  1052. Formats Size bytes at Address, in the time-honoured debug tradition, for
  1053. data dump purposes
  1054. Arguments:
  1055. Address - start of buffer
  1056. Size - number of bytes
  1057. ElementSize - size of each word element in bytes
  1058. Buffer - pointer to output buffer, assumed to be large enough
  1059. Return Value:
  1060. DWORD - number of bytes formatted
  1061. --*/
  1062. {
  1063. //
  1064. // we (currently) only understand DWORD, WORD and BYTE dumps
  1065. //
  1066. if ((ElementSize != sizeof(DWORD)) && (ElementSize != sizeof(WORD))) {
  1067. ElementSize = sizeof(BYTE);
  1068. }
  1069. static char spaces[] = " "; // 15 * 3 + 2
  1070. int i, len;
  1071. len = min(Size, 16);
  1072. rsprintf(Buffer, "%08x ", Address);
  1073. //
  1074. // dump the hex representation of each character or word - up to 16 per line
  1075. //
  1076. DWORD offset = 10;
  1077. for (i = 0; i < len; i += ElementSize) {
  1078. DWORD value;
  1079. LPSTR formatString;
  1080. switch (ElementSize) {
  1081. case 4:
  1082. formatString = "%08x ";
  1083. value = *(LPDWORD)&Address[i];
  1084. break;
  1085. case 2:
  1086. formatString = "%04x ";
  1087. value = *(LPWORD)&Address[i] & 0xffff;
  1088. break;
  1089. default:
  1090. formatString = ((i & 15) == 7) ? "%02.2x-" : "%02.2x ";
  1091. value = Address[i] & 0xff;
  1092. break;
  1093. }
  1094. rsprintf(&Buffer[offset], formatString, value);
  1095. offset += ElementSize * 2 + 1;
  1096. }
  1097. //
  1098. // write as many spaces as required to tab to ASCII field
  1099. //
  1100. memcpy(&Buffer[offset], spaces, (16 - len) * 3 + 2);
  1101. offset += (16 - len) * 3 + 2;
  1102. //
  1103. // dump ASCII representation of each character
  1104. //
  1105. for (i = 0; i < len; ++i) {
  1106. char ch;
  1107. ch = Address[i];
  1108. Buffer[offset + i] = ((ch < 32) || (ch > 127)) ? '.' : ch;
  1109. }
  1110. Buffer[offset + i++] = '\r';
  1111. Buffer[offset + i++] = '\n';
  1112. Buffer[offset + i] = '\0';
  1113. return len;
  1114. }
  1115. VOID
  1116. InternetAssert(
  1117. IN LPSTR Assertion,
  1118. IN LPSTR FileName,
  1119. IN DWORD LineNumber
  1120. )
  1121. /*++
  1122. Routine Description:
  1123. displays assertion message at debugger and raised breakpoint exception
  1124. Arguments:
  1125. Assertion - string describing assertion which failed
  1126. FileName - module where assertion failure occurred
  1127. LineNumber - at this line number
  1128. Return Value:
  1129. None.
  1130. --*/
  1131. {
  1132. char buffer[512];
  1133. rsprintf(buffer,
  1134. "\n"
  1135. "*** Urlmon Assertion failed: %s\n"
  1136. "*** Source file: %s\n"
  1137. "*** Source line: %d\n"
  1138. "*** Thread %08x\n"
  1139. "\n",
  1140. Assertion,
  1141. FileName,
  1142. LineNumber,
  1143. GetCurrentThreadId()
  1144. );
  1145. InternetDebugOut(buffer, TRUE);
  1146. //
  1147. // break to the debugger, unless it is requested that we don't
  1148. //
  1149. if (!(InternetDebugControlFlags & DBG_NO_ASSERT_BREAK)) {
  1150. DebugBreak();
  1151. }
  1152. }
  1153. VOID
  1154. InternetGetDebugVariable(
  1155. IN LPSTR lpszVariableName,
  1156. OUT LPDWORD lpdwVariable
  1157. )
  1158. /*++
  1159. Routine Description:
  1160. Get debug variable. First examine environment, then registry
  1161. Arguments:
  1162. lpszVariableName - variable name
  1163. lpdwVariable - returned variable
  1164. Return Value:
  1165. None.
  1166. --*/
  1167. {
  1168. DWORD len;
  1169. char varbuf[ENVIRONMENT_VARIABLE_BUFFER_LENGTH];
  1170. //
  1171. // get the debug variables first from the environment, then - if not there -
  1172. // from the registry
  1173. //
  1174. len = GetEnvironmentVariable(lpszVariableName, varbuf, sizeof(varbuf));
  1175. if (len && len < sizeof(varbuf)) {
  1176. *lpdwVariable = (DWORD)strtoul(varbuf, NULL, 0);
  1177. } else {
  1178. InternetReadRegistryDword(lpszVariableName, lpdwVariable);
  1179. }
  1180. }
  1181. PRIVATE
  1182. VOID
  1183. InternetGetDebugVariableString(
  1184. IN LPSTR lpszVariableName,
  1185. OUT LPSTR lpszVariable,
  1186. IN DWORD dwVariableLen
  1187. )
  1188. /*++
  1189. Routine Description:
  1190. Get debug variable string. First examine environment, then registry
  1191. Arguments:
  1192. lpszVariableName - variable name
  1193. lpszVariable - returned string variable
  1194. dwVariableLen - size of buffer
  1195. Return Value:
  1196. None.
  1197. --*/
  1198. {
  1199. if (GetEnvironmentVariable(lpszVariableName, lpszVariable, dwVariableLen) == 0) {
  1200. char buf[MAX_PATH + 1];
  1201. DWORD len = min(sizeof(buf), dwVariableLen);
  1202. if (InternetReadRegistryString(lpszVariableName, buf, &len) == ERROR_SUCCESS) {
  1203. memcpy(lpszVariable, buf, len + 1);
  1204. }
  1205. }
  1206. }
  1207. LPSTR
  1208. InternetMapError(
  1209. IN DWORD Error
  1210. )
  1211. /*++
  1212. Routine Description:
  1213. Map error code to string. Try to get all errors that might ever be returned
  1214. by an Internet function
  1215. Arguments:
  1216. Error - code to map
  1217. Return Value:
  1218. LPSTR - pointer to symbolic error name
  1219. --*/
  1220. {
  1221. switch (Error) {
  1222. //
  1223. // WINERROR errors
  1224. //
  1225. CASE_OF(ERROR_SUCCESS);
  1226. CASE_OF(S_FALSE);
  1227. CASE_OF(ERROR_FILE_NOT_FOUND);
  1228. CASE_OF(ERROR_PATH_NOT_FOUND);
  1229. CASE_OF(ERROR_TOO_MANY_OPEN_FILES);
  1230. CASE_OF(ERROR_ACCESS_DENIED);
  1231. CASE_OF(ERROR_INVALID_HANDLE);
  1232. CASE_OF(ERROR_ARENA_TRASHED);
  1233. CASE_OF(ERROR_NOT_ENOUGH_MEMORY);
  1234. CASE_OF(ERROR_INVALID_BLOCK);
  1235. CASE_OF(ERROR_BAD_ENVIRONMENT);
  1236. CASE_OF(ERROR_BAD_FORMAT);
  1237. CASE_OF(ERROR_INVALID_ACCESS);
  1238. CASE_OF(ERROR_INVALID_DATA);
  1239. CASE_OF(ERROR_OUTOFMEMORY);
  1240. CASE_OF(ERROR_INVALID_DRIVE);
  1241. CASE_OF(ERROR_CURRENT_DIRECTORY);
  1242. CASE_OF(ERROR_NOT_SAME_DEVICE);
  1243. CASE_OF(ERROR_NO_MORE_FILES);
  1244. CASE_OF(ERROR_WRITE_PROTECT);
  1245. CASE_OF(ERROR_BAD_UNIT);
  1246. CASE_OF(ERROR_NOT_READY);
  1247. CASE_OF(ERROR_BAD_COMMAND);
  1248. CASE_OF(ERROR_CRC);
  1249. CASE_OF(ERROR_BAD_LENGTH);
  1250. CASE_OF(ERROR_SEEK);
  1251. CASE_OF(ERROR_NOT_DOS_DISK);
  1252. CASE_OF(ERROR_SECTOR_NOT_FOUND);
  1253. CASE_OF(ERROR_OUT_OF_PAPER);
  1254. CASE_OF(ERROR_WRITE_FAULT);
  1255. CASE_OF(ERROR_READ_FAULT);
  1256. CASE_OF(ERROR_GEN_FAILURE);
  1257. CASE_OF(ERROR_SHARING_VIOLATION);
  1258. CASE_OF(ERROR_LOCK_VIOLATION);
  1259. CASE_OF(ERROR_WRONG_DISK);
  1260. CASE_OF(ERROR_SHARING_BUFFER_EXCEEDED);
  1261. CASE_OF(ERROR_HANDLE_EOF);
  1262. CASE_OF(ERROR_HANDLE_DISK_FULL);
  1263. CASE_OF(ERROR_NOT_SUPPORTED);
  1264. CASE_OF(ERROR_REM_NOT_LIST);
  1265. CASE_OF(ERROR_DUP_NAME);
  1266. CASE_OF(ERROR_BAD_NETPATH);
  1267. CASE_OF(ERROR_NETWORK_BUSY);
  1268. CASE_OF(ERROR_DEV_NOT_EXIST);
  1269. CASE_OF(ERROR_TOO_MANY_CMDS);
  1270. CASE_OF(ERROR_ADAP_HDW_ERR);
  1271. CASE_OF(ERROR_BAD_NET_RESP);
  1272. CASE_OF(ERROR_UNEXP_NET_ERR);
  1273. CASE_OF(ERROR_BAD_REM_ADAP);
  1274. CASE_OF(ERROR_PRINTQ_FULL);
  1275. CASE_OF(ERROR_NO_SPOOL_SPACE);
  1276. CASE_OF(ERROR_PRINT_CANCELLED);
  1277. CASE_OF(ERROR_NETNAME_DELETED);
  1278. CASE_OF(ERROR_NETWORK_ACCESS_DENIED);
  1279. CASE_OF(ERROR_BAD_DEV_TYPE);
  1280. CASE_OF(ERROR_BAD_NET_NAME);
  1281. CASE_OF(ERROR_TOO_MANY_NAMES);
  1282. CASE_OF(ERROR_TOO_MANY_SESS);
  1283. CASE_OF(ERROR_SHARING_PAUSED);
  1284. CASE_OF(ERROR_REQ_NOT_ACCEP);
  1285. CASE_OF(ERROR_REDIR_PAUSED);
  1286. CASE_OF(ERROR_FILE_EXISTS);
  1287. CASE_OF(ERROR_CANNOT_MAKE);
  1288. CASE_OF(ERROR_FAIL_I24);
  1289. CASE_OF(ERROR_OUT_OF_STRUCTURES);
  1290. CASE_OF(ERROR_ALREADY_ASSIGNED);
  1291. CASE_OF(ERROR_INVALID_PASSWORD);
  1292. CASE_OF(ERROR_INVALID_PARAMETER);
  1293. CASE_OF(ERROR_NET_WRITE_FAULT);
  1294. CASE_OF(ERROR_NO_PROC_SLOTS);
  1295. CASE_OF(ERROR_TOO_MANY_SEMAPHORES);
  1296. CASE_OF(ERROR_EXCL_SEM_ALREADY_OWNED);
  1297. CASE_OF(ERROR_SEM_IS_SET);
  1298. CASE_OF(ERROR_TOO_MANY_SEM_REQUESTS);
  1299. CASE_OF(ERROR_INVALID_AT_INTERRUPT_TIME);
  1300. CASE_OF(ERROR_SEM_OWNER_DIED);
  1301. CASE_OF(ERROR_SEM_USER_LIMIT);
  1302. CASE_OF(ERROR_DISK_CHANGE);
  1303. CASE_OF(ERROR_DRIVE_LOCKED);
  1304. CASE_OF(ERROR_BROKEN_PIPE);
  1305. CASE_OF(ERROR_OPEN_FAILED);
  1306. CASE_OF(ERROR_BUFFER_OVERFLOW);
  1307. CASE_OF(ERROR_DISK_FULL);
  1308. CASE_OF(ERROR_NO_MORE_SEARCH_HANDLES);
  1309. CASE_OF(ERROR_INVALID_TARGET_HANDLE);
  1310. CASE_OF(ERROR_INVALID_CATEGORY);
  1311. CASE_OF(ERROR_INVALID_VERIFY_SWITCH);
  1312. CASE_OF(ERROR_BAD_DRIVER_LEVEL);
  1313. CASE_OF(ERROR_CALL_NOT_IMPLEMENTED);
  1314. CASE_OF(ERROR_SEM_TIMEOUT);
  1315. CASE_OF(ERROR_INSUFFICIENT_BUFFER);
  1316. CASE_OF(ERROR_INVALID_NAME);
  1317. CASE_OF(ERROR_INVALID_LEVEL);
  1318. CASE_OF(ERROR_NO_VOLUME_LABEL);
  1319. CASE_OF(ERROR_MOD_NOT_FOUND);
  1320. CASE_OF(ERROR_PROC_NOT_FOUND);
  1321. CASE_OF(ERROR_WAIT_NO_CHILDREN);
  1322. CASE_OF(ERROR_CHILD_NOT_COMPLETE);
  1323. CASE_OF(ERROR_DIRECT_ACCESS_HANDLE);
  1324. CASE_OF(ERROR_NEGATIVE_SEEK);
  1325. CASE_OF(ERROR_SEEK_ON_DEVICE);
  1326. CASE_OF(ERROR_DIR_NOT_ROOT);
  1327. CASE_OF(ERROR_DIR_NOT_EMPTY);
  1328. CASE_OF(ERROR_PATH_BUSY);
  1329. CASE_OF(ERROR_SYSTEM_TRACE);
  1330. CASE_OF(ERROR_INVALID_EVENT_COUNT);
  1331. CASE_OF(ERROR_TOO_MANY_MUXWAITERS);
  1332. CASE_OF(ERROR_INVALID_LIST_FORMAT);
  1333. CASE_OF(ERROR_BAD_ARGUMENTS);
  1334. CASE_OF(ERROR_BAD_PATHNAME);
  1335. CASE_OF(ERROR_BUSY);
  1336. CASE_OF(ERROR_CANCEL_VIOLATION);
  1337. CASE_OF(ERROR_ALREADY_EXISTS);
  1338. CASE_OF(ERROR_FILENAME_EXCED_RANGE);
  1339. CASE_OF(ERROR_LOCKED);
  1340. CASE_OF(ERROR_NESTING_NOT_ALLOWED);
  1341. CASE_OF(ERROR_BAD_PIPE);
  1342. CASE_OF(ERROR_PIPE_BUSY);
  1343. CASE_OF(ERROR_NO_DATA);
  1344. CASE_OF(ERROR_PIPE_NOT_CONNECTED);
  1345. CASE_OF(ERROR_MORE_DATA);
  1346. CASE_OF(ERROR_NO_MORE_ITEMS);
  1347. CASE_OF(ERROR_NOT_OWNER);
  1348. CASE_OF(ERROR_PARTIAL_COPY);
  1349. CASE_OF(ERROR_MR_MID_NOT_FOUND);
  1350. CASE_OF(ERROR_INVALID_ADDRESS);
  1351. CASE_OF(ERROR_PIPE_CONNECTED);
  1352. CASE_OF(ERROR_PIPE_LISTENING);
  1353. CASE_OF(ERROR_OPERATION_ABORTED);
  1354. CASE_OF(ERROR_IO_INCOMPLETE);
  1355. CASE_OF(ERROR_IO_PENDING);
  1356. CASE_OF(ERROR_NOACCESS);
  1357. CASE_OF(ERROR_STACK_OVERFLOW);
  1358. CASE_OF(ERROR_INVALID_FLAGS);
  1359. CASE_OF(ERROR_NO_TOKEN);
  1360. CASE_OF(ERROR_BADDB);
  1361. CASE_OF(ERROR_BADKEY);
  1362. CASE_OF(ERROR_CANTOPEN);
  1363. CASE_OF(ERROR_CANTREAD);
  1364. CASE_OF(ERROR_CANTWRITE);
  1365. CASE_OF(ERROR_REGISTRY_RECOVERED);
  1366. CASE_OF(ERROR_REGISTRY_CORRUPT);
  1367. CASE_OF(ERROR_REGISTRY_IO_FAILED);
  1368. CASE_OF(ERROR_NOT_REGISTRY_FILE);
  1369. CASE_OF(ERROR_KEY_DELETED);
  1370. CASE_OF(ERROR_CIRCULAR_DEPENDENCY);
  1371. CASE_OF(ERROR_SERVICE_NOT_ACTIVE);
  1372. CASE_OF(ERROR_DLL_INIT_FAILED);
  1373. CASE_OF(ERROR_CANCELLED);
  1374. CASE_OF(ERROR_BAD_USERNAME);
  1375. CASE_OF(ERROR_LOGON_FAILURE);
  1376. CASE_OF(WAIT_FAILED);
  1377. //CASE_OF(WAIT_ABANDONED_0);
  1378. CASE_OF(WAIT_TIMEOUT);
  1379. CASE_OF(WAIT_IO_COMPLETION);
  1380. //CASE_OF(STILL_ACTIVE);
  1381. CASE_OF(RPC_S_INVALID_STRING_BINDING);
  1382. CASE_OF(RPC_S_WRONG_KIND_OF_BINDING);
  1383. CASE_OF(RPC_S_INVALID_BINDING);
  1384. CASE_OF(RPC_S_PROTSEQ_NOT_SUPPORTED);
  1385. CASE_OF(RPC_S_INVALID_RPC_PROTSEQ);
  1386. CASE_OF(RPC_S_INVALID_STRING_UUID);
  1387. CASE_OF(RPC_S_INVALID_ENDPOINT_FORMAT);
  1388. CASE_OF(RPC_S_INVALID_NET_ADDR);
  1389. CASE_OF(RPC_S_NO_ENDPOINT_FOUND);
  1390. CASE_OF(RPC_S_INVALID_TIMEOUT);
  1391. CASE_OF(RPC_S_OBJECT_NOT_FOUND);
  1392. CASE_OF(RPC_S_ALREADY_REGISTERED);
  1393. CASE_OF(RPC_S_TYPE_ALREADY_REGISTERED);
  1394. CASE_OF(RPC_S_ALREADY_LISTENING);
  1395. CASE_OF(RPC_S_NO_PROTSEQS_REGISTERED);
  1396. CASE_OF(RPC_S_NOT_LISTENING);
  1397. CASE_OF(RPC_S_UNKNOWN_MGR_TYPE);
  1398. CASE_OF(RPC_S_UNKNOWN_IF);
  1399. CASE_OF(RPC_S_NO_BINDINGS);
  1400. CASE_OF(RPC_S_NO_PROTSEQS);
  1401. CASE_OF(RPC_S_CANT_CREATE_ENDPOINT);
  1402. CASE_OF(RPC_S_OUT_OF_RESOURCES);
  1403. CASE_OF(RPC_S_SERVER_UNAVAILABLE);
  1404. CASE_OF(RPC_S_SERVER_TOO_BUSY);
  1405. CASE_OF(RPC_S_INVALID_NETWORK_OPTIONS);
  1406. CASE_OF(RPC_S_NO_CALL_ACTIVE);
  1407. CASE_OF(RPC_S_CALL_FAILED);
  1408. CASE_OF(RPC_S_CALL_FAILED_DNE);
  1409. CASE_OF(RPC_S_PROTOCOL_ERROR);
  1410. CASE_OF(RPC_S_UNSUPPORTED_TRANS_SYN);
  1411. CASE_OF(RPC_S_UNSUPPORTED_TYPE);
  1412. CASE_OF(RPC_S_INVALID_TAG);
  1413. CASE_OF(RPC_S_INVALID_BOUND);
  1414. CASE_OF(RPC_S_NO_ENTRY_NAME);
  1415. CASE_OF(RPC_S_INVALID_NAME_SYNTAX);
  1416. CASE_OF(RPC_S_UNSUPPORTED_NAME_SYNTAX);
  1417. CASE_OF(RPC_S_UUID_NO_ADDRESS);
  1418. CASE_OF(RPC_S_DUPLICATE_ENDPOINT);
  1419. CASE_OF(RPC_S_UNKNOWN_AUTHN_TYPE);
  1420. CASE_OF(RPC_S_MAX_CALLS_TOO_SMALL);
  1421. CASE_OF(RPC_S_STRING_TOO_LONG);
  1422. CASE_OF(RPC_S_PROTSEQ_NOT_FOUND);
  1423. CASE_OF(RPC_S_PROCNUM_OUT_OF_RANGE);
  1424. CASE_OF(RPC_S_BINDING_HAS_NO_AUTH);
  1425. CASE_OF(RPC_S_UNKNOWN_AUTHN_SERVICE);
  1426. CASE_OF(RPC_S_UNKNOWN_AUTHN_LEVEL);
  1427. CASE_OF(RPC_S_INVALID_AUTH_IDENTITY);
  1428. CASE_OF(RPC_S_UNKNOWN_AUTHZ_SERVICE);
  1429. CASE_OF(EPT_S_INVALID_ENTRY);
  1430. CASE_OF(EPT_S_CANT_PERFORM_OP);
  1431. CASE_OF(EPT_S_NOT_REGISTERED);
  1432. CASE_OF(RPC_S_NOTHING_TO_EXPORT);
  1433. CASE_OF(RPC_S_INCOMPLETE_NAME);
  1434. CASE_OF(RPC_S_INVALID_VERS_OPTION);
  1435. CASE_OF(RPC_S_NO_MORE_MEMBERS);
  1436. CASE_OF(RPC_S_NOT_ALL_OBJS_UNEXPORTED);
  1437. CASE_OF(RPC_S_INTERFACE_NOT_FOUND);
  1438. CASE_OF(RPC_S_ENTRY_ALREADY_EXISTS);
  1439. CASE_OF(RPC_S_ENTRY_NOT_FOUND);
  1440. CASE_OF(RPC_S_NAME_SERVICE_UNAVAILABLE);
  1441. CASE_OF(RPC_S_INVALID_NAF_ID);
  1442. CASE_OF(RPC_S_CANNOT_SUPPORT);
  1443. CASE_OF(RPC_S_NO_CONTEXT_AVAILABLE);
  1444. CASE_OF(RPC_S_INTERNAL_ERROR);
  1445. CASE_OF(RPC_S_ZERO_DIVIDE);
  1446. CASE_OF(RPC_S_ADDRESS_ERROR);
  1447. CASE_OF(RPC_S_FP_DIV_ZERO);
  1448. CASE_OF(RPC_S_FP_UNDERFLOW);
  1449. CASE_OF(RPC_S_FP_OVERFLOW);
  1450. CASE_OF(RPC_X_NO_MORE_ENTRIES);
  1451. CASE_OF(RPC_X_SS_CHAR_TRANS_OPEN_FAIL);
  1452. CASE_OF(RPC_X_SS_CHAR_TRANS_SHORT_FILE);
  1453. CASE_OF(RPC_X_SS_IN_NULL_CONTEXT);
  1454. CASE_OF(RPC_X_SS_CONTEXT_DAMAGED);
  1455. CASE_OF(RPC_X_SS_HANDLES_MISMATCH);
  1456. CASE_OF(RPC_X_SS_CANNOT_GET_CALL_HANDLE);
  1457. CASE_OF(RPC_X_NULL_REF_POINTER);
  1458. CASE_OF(RPC_X_ENUM_VALUE_OUT_OF_RANGE);
  1459. CASE_OF(RPC_X_BYTE_COUNT_TOO_SMALL);
  1460. CASE_OF(RPC_X_BAD_STUB_DATA);
  1461. default:
  1462. return "?";
  1463. }
  1464. }
  1465. //
  1466. // private functions
  1467. //
  1468. PRIVATE
  1469. LPSTR
  1470. ExtractFileName(
  1471. IN LPSTR Module,
  1472. OUT LPSTR Buf
  1473. )
  1474. {
  1475. LPSTR filename;
  1476. LPSTR extension;
  1477. int len;
  1478. filename = strrchr(Module, '\\');
  1479. extension = strrchr(Module, '.');
  1480. if (filename) {
  1481. ++filename;
  1482. } else {
  1483. filename = Module;
  1484. }
  1485. if (!extension) {
  1486. extension = filename + strlen(filename);
  1487. }
  1488. len = (int) (extension - filename);
  1489. memcpy(Buf, filename, len);
  1490. Buf[len] = '\0';
  1491. return Buf;
  1492. }
  1493. PRIVATE
  1494. LPSTR
  1495. SetDebugPrefix(
  1496. IN LPSTR Buffer
  1497. )
  1498. {
  1499. HRESULT hr = S_OK;
  1500. CUrlMkTls tls(hr); // hr passed by reference!
  1501. if (FAILED(hr))
  1502. return NULL;
  1503. LPDEBUG_URLMON_FUNC_RECORD pCurrentFunction = tls->Stack;
  1504. if (!pCurrentFunction) {
  1505. return NULL;
  1506. }
  1507. if (InternetDebugControlFlags & DBG_ENTRY_TIME) {
  1508. if (InternetDebugControlFlags & (DBG_DELTA_TIME | DBG_CUMULATIVE_TIME))
  1509. {
  1510. DWORD ticks;
  1511. DWORD ticksNow;
  1512. ticksNow = GetTickCountWrap();
  1513. ticks = ticksNow - ((InternetDebugControlFlags & DBG_CUMULATIVE_TIME)
  1514. ? InternetDebugStartTime
  1515. : pCurrentFunction->LastTime);
  1516. Buffer += rsprintf(Buffer,
  1517. "% 5d.%3d ",
  1518. ticks / 1000,
  1519. ticks % 1000
  1520. );
  1521. if (InternetDebugControlFlags & DBG_DELTA_TIME) {
  1522. pCurrentFunction->LastTime = ticksNow;
  1523. }
  1524. } else {
  1525. SYSTEMTIME timeNow;
  1526. InternetDebugGetLocalTime(&timeNow, NULL);
  1527. Buffer += rsprintf(Buffer,
  1528. "%02d:%02d:%02d.%03d ",
  1529. timeNow.wHour,
  1530. timeNow.wMinute,
  1531. timeNow.wSecond,
  1532. timeNow.wMilliseconds
  1533. );
  1534. }
  1535. }
  1536. /*
  1537. if (InternetDebugControlFlags & DBG_LEVEL_INDICATOR) {
  1538. Buffer += rsprintf(Buffer, );
  1539. }
  1540. */
  1541. if (InternetDebugControlFlags & DBG_THREAD_INFO) {
  1542. //
  1543. // thread id
  1544. //
  1545. Buffer += rsprintf(Buffer, "%08x", tls->ThreadId);
  1546. //
  1547. // INTERNET_THREAD_INFO address
  1548. //
  1549. if (InternetDebugControlFlags & DBG_THREAD_INFO_ADR) {
  1550. Buffer += rsprintf(Buffer, ":%08x", tls);
  1551. }
  1552. *Buffer++ = ' ';
  1553. }
  1554. if (InternetDebugControlFlags & DBG_CALL_DEPTH) {
  1555. Buffer += rsprintf(Buffer, "%03d ", tls->CallDepth);
  1556. }
  1557. for (int i = 0; i < tls->IndentIncrement; ++i) {
  1558. *Buffer++ = ' ';
  1559. }
  1560. //
  1561. // if we are not debugging the category - i.e we got here via a requirement
  1562. // to display an error, or we are in a function that does not have a
  1563. // DEBUG_ENTER - then prefix the string with the current function name
  1564. // (obviously misleading if the function doesn't have a DEBUG_ENTER)
  1565. //
  1566. if (pCurrentFunction != NULL) {
  1567. if (!(pCurrentFunction->Category & InternetDebugCategoryFlags)) {
  1568. Buffer += rsprintf(Buffer, "%s(): ", pCurrentFunction->Function);
  1569. }
  1570. }
  1571. return Buffer;
  1572. }
  1573. int dprintf(char * format, ...) {
  1574. va_list args;
  1575. char buf[PRINTF_STACK_BUFFER_LENGTH];
  1576. int n;
  1577. va_start(args, format);
  1578. n = _sprintf(buf, format, args);
  1579. va_end(args);
  1580. OutputDebugString(buf);
  1581. return n;
  1582. }
  1583. LPSTR
  1584. SourceFilename(
  1585. LPSTR Filespec
  1586. )
  1587. {
  1588. if (!Filespec) {
  1589. return "?";
  1590. }
  1591. LPSTR p;
  1592. if (p = strrchr(Filespec, '\\')) {
  1593. //
  1594. // we want e.g. common\debugmem.cxx, but get
  1595. // common\..\win32\debugmem.cxx. Bah!
  1596. //
  1597. //LPSTR q;
  1598. //
  1599. //if (q = strrchr(p - 1, '\\')) {
  1600. // p = q;
  1601. //}
  1602. }
  1603. return p ? p + 1 : Filespec;
  1604. }
  1605. typedef BOOL (* SYMINITIALIZE)(HANDLE, LPSTR, BOOL);
  1606. typedef BOOL (* SYMLOADMODULE)(HANDLE, HANDLE, PSTR, PSTR, DWORD, DWORD);
  1607. typedef BOOL (* SYMGETSYMFROMADDR)(HANDLE, DWORD, PDWORD, PIMAGEHLP_SYMBOL);
  1608. typedef BOOL (* SYMCLEANUP)(HANDLE);
  1609. PRIVATE HMODULE hSymLib = NULL;
  1610. PRIVATE SYMINITIALIZE pSymInitialize = NULL;
  1611. PRIVATE SYMLOADMODULE pSymLoadModule = NULL;
  1612. PRIVATE SYMGETSYMFROMADDR pSymGetSymFromAddr = NULL;
  1613. PRIVATE SYMCLEANUP pSymCleanup = NULL;
  1614. VOID
  1615. InitSymLib(
  1616. VOID
  1617. )
  1618. {
  1619. if (hSymLib == NULL) {
  1620. hSymLib = LoadLibrary("IMAGEHLP.DLL");
  1621. if (hSymLib != NULL) {
  1622. pSymInitialize = (SYMINITIALIZE)GetProcAddress(hSymLib,
  1623. "SymInitialize"
  1624. );
  1625. pSymLoadModule = (SYMLOADMODULE)GetProcAddress(hSymLib,
  1626. "SymLoadModule"
  1627. );
  1628. pSymGetSymFromAddr = (SYMGETSYMFROMADDR)GetProcAddress(hSymLib,
  1629. "SymGetSymFromAddr"
  1630. );
  1631. pSymCleanup = (SYMCLEANUP)GetProcAddress(hSymLib,
  1632. "SymCleanup"
  1633. );
  1634. if (!pSymInitialize
  1635. || !pSymLoadModule
  1636. || !pSymGetSymFromAddr
  1637. || !pSymCleanup) {
  1638. FreeLibrary(hSymLib);
  1639. hSymLib = NULL;
  1640. pSymInitialize = NULL;
  1641. pSymLoadModule = NULL;
  1642. pSymGetSymFromAddr = NULL;
  1643. pSymCleanup = NULL;
  1644. return;
  1645. }
  1646. }
  1647. pSymInitialize(GetCurrentProcess(), NULL, FALSE);
  1648. //SymInitialize(GetCurrentProcess(), NULL, TRUE);
  1649. pSymLoadModule(GetCurrentProcess(), NULL, "URLMON.DLL", "URLMON", 0, 0);
  1650. }
  1651. }
  1652. VOID
  1653. TermSymLib(
  1654. VOID
  1655. )
  1656. {
  1657. if (pSymCleanup) {
  1658. pSymCleanup(GetCurrentProcess());
  1659. FreeLibrary(hSymLib);
  1660. }
  1661. }
  1662. LPSTR
  1663. GetDebugSymbol(
  1664. DWORD Address,
  1665. LPDWORD Offset
  1666. )
  1667. {
  1668. *Offset = Address;
  1669. if (!pSymGetSymFromAddr) {
  1670. return "";
  1671. }
  1672. //
  1673. // BUGBUG - only one caller at a time please
  1674. //
  1675. static char symBuf[512];
  1676. //((PIMAGEHLP_SYMBOL)symBuf)->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL);
  1677. ((PIMAGEHLP_SYMBOL)symBuf)->SizeOfStruct = sizeof(symBuf);
  1678. ((PIMAGEHLP_SYMBOL)symBuf)->MaxNameLength = sizeof(symBuf) - sizeof(IMAGEHLP_SYMBOL);
  1679. if (!pSymGetSymFromAddr(GetCurrentProcess(),
  1680. Address,
  1681. Offset,
  1682. (PIMAGEHLP_SYMBOL)symBuf)) {
  1683. ((PIMAGEHLP_SYMBOL)symBuf)->Name[0] = '\0';
  1684. }
  1685. return ((PIMAGEHLP_SYMBOL)symBuf)->Name;
  1686. }
  1687. #if defined(i386)
  1688. VOID
  1689. x86SleazeCallStack(
  1690. OUT LPVOID * lplpvStack,
  1691. IN DWORD dwStackCount,
  1692. IN LPVOID * Ebp
  1693. )
  1694. /*++
  1695. Routine Description:
  1696. Similar to x86SleazeCallersAddress but gathers a variable number of return
  1697. addresses. We assume all functions have stack frame
  1698. Arguments:
  1699. lplpvStack - pointer to returned array of caller's addresses
  1700. dwStackCount - number of elements in lplpvStack
  1701. Ebp - starting Ebp if not 0, else use current stack
  1702. Return Value:
  1703. None.
  1704. --*/
  1705. {
  1706. DWORD my_esp;
  1707. _asm mov my_esp, esp;
  1708. __try {
  1709. if (Ebp == 0) {
  1710. Ebp = (LPVOID *)(&lplpvStack - 2);
  1711. }
  1712. while (dwStackCount--) {
  1713. if (((DWORD)Ebp > my_esp + 0x10000) || ((DWORD)Ebp < my_esp - 0x10000)) {
  1714. break;
  1715. }
  1716. *lplpvStack++ = *(Ebp + 1);
  1717. Ebp = (LPVOID *)*Ebp;
  1718. if (((DWORD)Ebp <= 0x10000)
  1719. || ((DWORD)Ebp >= 0x80000000)
  1720. || ((DWORD)Ebp & 3)
  1721. || ((DWORD)Ebp > my_esp + 0x10000)
  1722. || ((DWORD)Ebp < my_esp - 0x10000)) {
  1723. break;
  1724. }
  1725. }
  1726. } __except(EXCEPTION_EXECUTE_HANDLER) {
  1727. }
  1728. }
  1729. VOID
  1730. x86SleazeCallersAddress(
  1731. LPVOID* pCaller,
  1732. LPVOID* pCallersCaller
  1733. )
  1734. /*++
  1735. Routine Description:
  1736. This is a sleazy function that reads return addresses out of the stack/
  1737. frame pointer (ebp). We pluck out the return address of the function
  1738. that called THE FUNCTION THAT CALLED THIS FUNCTION, and the caller of
  1739. that function. Returning the return address of the function that called
  1740. this function is not interesting to that caller (almost worthy of Sir
  1741. Humphrey Appleby isn't it?)
  1742. Assumes:
  1743. my ebp => | caller's ebp |
  1744. | caller's eip |
  1745. | arg #1 | (pCaller)
  1746. | arg #2 | (pCallersCaller
  1747. Arguments:
  1748. pCaller - place where we return addres of function that called
  1749. the function that called this function
  1750. pCallersCaller - place where we return caller of above
  1751. Return Value:
  1752. None.
  1753. --*/
  1754. {
  1755. //
  1756. // this only works on x86 and only if not fpo functions!
  1757. //
  1758. LPVOID* ebp;
  1759. ebp = (PVOID*)&pCaller - 2; // told you it was sleazy
  1760. ebp = (PVOID*)*(PVOID*)ebp;
  1761. *pCaller = *(ebp + 1);
  1762. ebp = (PVOID*)*(PVOID*)ebp;
  1763. *pCallersCaller = *(ebp + 1);
  1764. }
  1765. #endif // defined(i386)
  1766. BOOL
  1767. InternetDebugGetLocalTime(
  1768. OUT SYSTEMTIME * pstLocalTime,
  1769. OUT DWORD * pdwMicroSec
  1770. )
  1771. {
  1772. #ifndef ENABLE_DEBUG
  1773. // QUICK HACK TO KEEP THINGS CLEAN AND STILL MEASURE WITH HIGH PERFORMANCE
  1774. // COUNTER
  1775. static BOOL pcTested = FALSE;
  1776. static LONGLONG ftInit; // initial local time
  1777. static LONGLONG pcInit; // initial perf counter
  1778. static LONGLONG pcFreq; // perf counter frequency
  1779. if (!pcTested)
  1780. {
  1781. pcTested = TRUE;
  1782. if (QueryPerformanceFrequency ((LARGE_INTEGER *) &pcFreq) && pcFreq)
  1783. {
  1784. QueryPerformanceCounter ((LARGE_INTEGER *) &pcInit);
  1785. SYSTEMTIME st;
  1786. GetLocalTime (&st);
  1787. SystemTimeToFileTime (&st, (FILETIME *) &ftInit);
  1788. }
  1789. }
  1790. if (!pcFreq)
  1791. GetLocalTime (pstLocalTime);
  1792. else
  1793. {
  1794. LONGLONG pcCurrent, ftCurrent;
  1795. QueryPerformanceCounter ((LARGE_INTEGER *) &pcCurrent);
  1796. ftCurrent = ftInit + ((10000000 * (pcCurrent - pcInit)) / pcFreq);
  1797. FileTimeToSystemTime ((FILETIME *) &ftCurrent, pstLocalTime);
  1798. }
  1799. return TRUE;
  1800. #else
  1801. if (!pcFreq)
  1802. GetLocalTime (pstLocalTime);
  1803. else
  1804. {
  1805. LONGLONG pcCurrent, ftCurrent;
  1806. QueryPerformanceCounter ((LARGE_INTEGER *) &pcCurrent);
  1807. ftCurrent = ftInit + ((10000000 * (pcCurrent - pcInit)) / pcFreq);
  1808. FileTimeToSystemTime ((FILETIME *) &ftCurrent, pstLocalTime);
  1809. }
  1810. return TRUE;
  1811. #endif // ENABLE_DEBUG
  1812. }
  1813. #endif // ENABLE_DEBUG