Source code of Windows XP (NT5)
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.

1128 lines
33 KiB

  1. /*===================================================================
  2. Microsoft Denali
  3. Microsoft Confidential.
  4. Copyright 1997 Microsoft Corporation. All Rights Reserved.
  5. Component: misc
  6. File: util.cpp
  7. Owner: DGottner
  8. This file contains debugger utility functions
  9. ===================================================================*/
  10. #include "denpre.h"
  11. #pragma hdrstop
  12. #include "vector.h"
  13. #include "debugger.h"
  14. #include "iiscnfg.h"
  15. #include "mdcommsg.h" // for RETURNCODETOHRESULT macro
  16. #include "memchk.h"
  17. #include "vecimpl.h"
  18. /* Win64: This struct is used to package data passed to the thread handler.
  19. * (3 DWORDs are too small in 64 bit world.)
  20. */
  21. struct DebugThreadCallArgs
  22. {
  23. DWORD dwMethod;
  24. IDebugApplication * pDebugAppln;
  25. void * pvArg;
  26. DebugThreadCallArgs(DWORD dwMethod = 0, IDebugApplication *pDebugAppln = 0, void *pvArg = 0)
  27. {
  28. this->dwMethod = dwMethod;
  29. this->pDebugAppln = pDebugAppln;
  30. this->pvArg = pvArg;
  31. }
  32. };
  33. // Published globals
  34. IProcessDebugManager * g_pPDM = NULL; // instance of debugger for this process.
  35. IDebugApplication * g_pDebugApp = NULL; // Root ASP application
  36. IDebugApplicationNode * g_pDebugAppRoot = NULL; // used to create hierarchy tree
  37. CViperActivity * g_pDebugActivity = NULL; // Debugger's activity
  38. DWORD g_dwDebugThreadId = 0; // Thread ID of viper activity
  39. // Globals for debugging
  40. static DWORD g_dwDenaliAppCookie; // Cookie to use to remove app
  41. static HANDLE g_hPDMTermEvent; // PDM terminate event
  42. static vector<DebugThreadCallArgs> *g_prgThreadCallArgs; // for new 64 bit interface.
  43. // This hash structure & CS is used by GetServerDebugRoot()
  44. struct CDebugNodeElem : CLinkElem
  45. {
  46. IDebugApplicationNode *m_pServerRoot;
  47. HRESULT Init(char *szKey, int cchKey)
  48. {
  49. char *szKeyAlloc = new char [cchKey + 1];
  50. if (!szKeyAlloc) return E_OUTOFMEMORY;
  51. return CLinkElem::Init(memcpy(szKeyAlloc, szKey, cchKey + 1), cchKey);
  52. }
  53. ~CDebugNodeElem()
  54. {
  55. if (m_pKey)
  56. delete m_pKey;
  57. }
  58. };
  59. static CHashTable g_HashMDPath2DebugRoot;
  60. static CRITICAL_SECTION g_csDebugLock; // Lock for g_hashMDPath2DebugRoot
  61. /*===================================================================
  62. InvokeDebuggerWithThreadSwitch
  63. Invoke Debugger (or Debugger UI) method from a correct thread
  64. using IDebugThreadCall.
  65. Parameters
  66. IDebugApplication *pDebugAppln to get to debugger UI
  67. DWORD iMethod which method to call
  68. void *Arg call argument
  69. Returns
  70. HRESULT
  71. ===================================================================*/
  72. // GUIDs for debugger events
  73. static const GUID DEBUGNOTIFY_ONPAGEBEGIN =
  74. { 0xfd6806c0, 0xdb89, 0x11d0, { 0x8f, 0x81, 0x0, 0x80, 0xc7, 0x3d, 0x6d, 0x96 } };
  75. static const GUID DEBUGNOTIFY_ONPAGEEND =
  76. { 0xfd6806c1, 0xdb89, 0x11d0, { 0x8f, 0x81, 0x0, 0x80, 0xc7, 0x3d, 0x6d, 0x96 } };
  77. static const GUID DEBUGNOTIFY_ON_REFRESH_BREAKPOINT =
  78. { 0xffcf4b38, 0xfa12, 0x11d0, { 0x8f, 0x3b, 0x0, 0xc0, 0x4f, 0xc3, 0x4d, 0xcc } };
  79. // Local class that implements IDebugCallback
  80. class CDebugThreadDebuggerCall : public IDebugThreadCall
  81. {
  82. public:
  83. STDMETHODIMP QueryInterface(const GUID &, void **);
  84. STDMETHODIMP_(ULONG) AddRef();
  85. STDMETHODIMP_(ULONG) Release();
  86. STDMETHODIMP ThreadCallHandler(DWORD_PTR, DWORD_PTR, DWORD_PTR);
  87. };
  88. HRESULT CDebugThreadDebuggerCall::QueryInterface
  89. (
  90. const GUID &iid,
  91. void **ppv
  92. )
  93. {
  94. if (iid == IID_IUnknown || iid == IID_IDebugThreadCall)
  95. {
  96. *ppv = this;
  97. return S_OK;
  98. }
  99. else
  100. {
  101. *ppv = NULL;
  102. return E_NOINTERFACE;
  103. }
  104. }
  105. ULONG CDebugThreadDebuggerCall::AddRef()
  106. {
  107. return 1;
  108. }
  109. ULONG CDebugThreadDebuggerCall::Release()
  110. {
  111. return 1;
  112. }
  113. HRESULT CDebugThreadDebuggerCall::ThreadCallHandler
  114. (
  115. DWORD_PTR iArg,
  116. DWORD_PTR ,
  117. DWORD_PTR
  118. )
  119. {
  120. // Get arguments
  121. DebugThreadCallArgs *pThreadCallArgs = &(*g_prgThreadCallArgs)[(int)iArg];
  122. IDebugApplication * pDebugAppln = pThreadCallArgs->pDebugAppln;
  123. DWORD dwMethod = pThreadCallArgs->dwMethod;
  124. void * pvArg = pThreadCallArgs->pvArg;
  125. // we won't reference the argument block again, so free it up now.
  126. pThreadCallArgs->dwMethod |= DEBUGGER_UNUSED_RECORD;
  127. BOOL fForceDebugger = (dwMethod & (DEBUGGER_UI_BRING_DOCUMENT_TO_TOP|DEBUGGER_UI_BRING_DOC_CONTEXT_TO_TOP)) != 0;
  128. BOOL fNeedDebuggerUI = (dwMethod & (DEBUGGER_UI_BRING_DOCUMENT_TO_TOP|DEBUGGER_UI_BRING_DOC_CONTEXT_TO_TOP)) != 0;
  129. BOOL fNeedNodeEvents = (dwMethod & DEBUGGER_ON_REMOVE_CHILD) != 0;
  130. BOOL fNeedDebugger = (dwMethod & ~DEBUGGER_ON_DESTROY) != 0;
  131. HRESULT hr = S_OK;
  132. IApplicationDebugger *pDebugger = NULL;
  133. IApplicationDebuggerUI *pDebuggerUI = NULL;
  134. IDebugApplicationNodeEvents *pNodeEvents = NULL;
  135. if (pDebugAppln == NULL)
  136. return E_POINTER;
  137. // Get the debugger
  138. if (fNeedDebugger)
  139. {
  140. hr = pDebugAppln->GetDebugger(&pDebugger);
  141. if (FAILED(hr))
  142. {
  143. // Debugger is not currently debugging our application.
  144. if (!fForceDebugger)
  145. return E_FAIL; // no debugger
  146. // Start the debugger and try again.
  147. hr = pDebugAppln->StartDebugSession();
  148. if (SUCCEEDED(hr))
  149. hr = pDebugAppln->GetDebugger(&pDebugger);
  150. }
  151. // Debugger UI is needed only for some methods
  152. if (SUCCEEDED(hr) && fNeedDebuggerUI)
  153. {
  154. hr = pDebugger->QueryInterface
  155. (
  156. IID_IApplicationDebuggerUI,
  157. reinterpret_cast<void **>(&pDebuggerUI)
  158. );
  159. }
  160. // Debugger UI is needed only for some methods
  161. if (SUCCEEDED(hr) && fNeedNodeEvents)
  162. {
  163. hr = pDebugger->QueryInterface
  164. (
  165. IID_IDebugApplicationNodeEvents,
  166. reinterpret_cast<void **>(&pNodeEvents)
  167. );
  168. }
  169. }
  170. // Call the desired method
  171. if (SUCCEEDED(hr))
  172. {
  173. switch (dwMethod)
  174. {
  175. case DEBUGGER_EVENT_ON_PAGEBEGIN:
  176. {
  177. hr = pDebugger->onDebuggerEvent
  178. (
  179. DEBUGNOTIFY_ONPAGEBEGIN,
  180. static_cast<IUnknown *>(pvArg)
  181. );
  182. break;
  183. }
  184. case DEBUGGER_EVENT_ON_PAGEEND:
  185. {
  186. hr = pDebugger->onDebuggerEvent
  187. (
  188. DEBUGNOTIFY_ONPAGEEND,
  189. static_cast<IUnknown *>(pvArg)
  190. );
  191. break;
  192. }
  193. case DEBUGGER_EVENT_ON_REFRESH_BREAKPOINT:
  194. {
  195. hr = pDebugger->onDebuggerEvent
  196. (
  197. DEBUGNOTIFY_ON_REFRESH_BREAKPOINT,
  198. static_cast<IUnknown *>(pvArg)
  199. );
  200. break;
  201. }
  202. case DEBUGGER_ON_REMOVE_CHILD:
  203. {
  204. hr = pNodeEvents->onRemoveChild
  205. (
  206. static_cast<IDebugApplicationNode *>(pvArg)
  207. );
  208. break;
  209. }
  210. case DEBUGGER_ON_DESTROY:
  211. {
  212. hr = static_cast<IDebugDocumentTextEvents *>(pvArg)->onDestroy();
  213. break;
  214. }
  215. case DEBUGGER_UI_BRING_DOCUMENT_TO_TOP:
  216. {
  217. hr = pDebuggerUI->BringDocumentToTop
  218. (
  219. static_cast<IDebugDocumentText *>(pvArg)
  220. );
  221. break;
  222. }
  223. case DEBUGGER_UI_BRING_DOC_CONTEXT_TO_TOP:
  224. {
  225. hr = pDebuggerUI->BringDocumentContextToTop
  226. (
  227. static_cast<IDebugDocumentContext *>(pvArg)
  228. );
  229. break;
  230. }
  231. default:
  232. hr = E_FAIL;
  233. break;
  234. }
  235. }
  236. // Cleanup
  237. if (pDebuggerUI) pDebuggerUI->Release();
  238. if (pNodeEvents) pNodeEvents->Release();
  239. if (pDebugger) pDebugger->Release();
  240. return hr;
  241. }
  242. // The function calls using IDebugThreadCall
  243. HRESULT InvokeDebuggerWithThreadSwitch
  244. (
  245. IDebugApplication *pDebugAppln,
  246. DWORD dwMethod,
  247. void *pvArg
  248. )
  249. {
  250. // take these arguments and package them up in the array. We will pass the
  251. // index to the callback handler.
  252. //
  253. // first look for a freed up element before creating a new one.
  254. for (int i = g_prgThreadCallArgs->length() - 1; i >= 0; --i)
  255. {
  256. DebugThreadCallArgs *pThreadCallArgs = &(*g_prgThreadCallArgs)[i];
  257. if (pThreadCallArgs->dwMethod & DEBUGGER_UNUSED_RECORD)
  258. {
  259. pThreadCallArgs->dwMethod = dwMethod;
  260. pThreadCallArgs->pDebugAppln = pDebugAppln;
  261. pThreadCallArgs->pvArg = pvArg;
  262. break;
  263. }
  264. }
  265. if (i < 0)
  266. {
  267. HRESULT hr = g_prgThreadCallArgs->append(DebugThreadCallArgs(dwMethod, pDebugAppln, pvArg));
  268. if (FAILED(hr))
  269. return hr;
  270. i = g_prgThreadCallArgs->length() - 1;
  271. }
  272. CDebugThreadDebuggerCall Call;
  273. return pDebugAppln->SynchronousCallInDebuggerThread
  274. (
  275. &Call, i, 0, 0
  276. );
  277. }
  278. /*===================================================================
  279. FCaesars
  280. Query registry to determine if default debugger is Caesar's
  281. (Script Debugger)
  282. ===================================================================*/
  283. BOOL FCaesars()
  284. {
  285. static BOOL fCaesars = 0xBADF00D;
  286. HKEY hKey = NULL;
  287. char szRegPath[_MAX_PATH];
  288. DWORD dwSize = sizeof szRegPath;
  289. // Check to see if Ceasers is registered as the JIT debugger on this machine.
  290. if (fCaesars == 0xBADF00D)
  291. {
  292. fCaesars = FALSE;
  293. if (RegOpenKey(HKEY_CLASSES_ROOT, _T("CLSID\\{834128A2-51F4-11D0-8F20-00805F2CD064}\\LocalServer32"), &hKey) == ERROR_SUCCESS)
  294. {
  295. if (RegQueryValueEx(hKey, NULL, NULL, NULL, (LPBYTE) szRegPath, &dwSize) == ERROR_SUCCESS)
  296. {
  297. char szFile[_MAX_FNAME];
  298. _splitpath(szRegPath, NULL, NULL, szFile, NULL);
  299. if (_stricmp(szFile, "msscrdbg") == 0)
  300. fCaesars = TRUE;
  301. }
  302. CloseHandle (hKey);
  303. }
  304. }
  305. return fCaesars;
  306. }
  307. /*===================================================================
  308. DestroyDocumentTree
  309. Recursively release all the nodes in a document tree.
  310. Parameters
  311. IDebugApplication *pDocRoot root of hierarchy to destroy
  312. ===================================================================*/
  313. void
  314. DestroyDocumentTree(IDebugApplicationNode *pDocRoot)
  315. {
  316. IEnumDebugApplicationNodes *pEnum;
  317. if (SUCCEEDED(pDocRoot->EnumChildren(&pEnum)) && pEnum != NULL)
  318. {
  319. IDebugApplicationNode *pDocNode;
  320. while (pEnum->Next(1, &pDocNode, NULL) == S_OK)
  321. DestroyDocumentTree(pDocNode);
  322. pEnum->Release();
  323. }
  324. // See if this is a directory node
  325. //
  326. IFileNode *pFileNode;
  327. if (SUCCEEDED(pDocRoot->QueryInterface(IID_IFileNode, reinterpret_cast<void **>(&pFileNode))))
  328. {
  329. // This is a directory node, only detach when its document count vanishes)
  330. if (pFileNode->DecrementDocumentCount() == 0)
  331. {
  332. pDocRoot->Detach();
  333. pDocRoot->Close();
  334. pDocRoot->Release();
  335. }
  336. pFileNode->Release();
  337. }
  338. else
  339. {
  340. // This node is a CTemplate (or one of its include files)
  341. pDocRoot->Detach();
  342. pDocRoot->Close();
  343. pDocRoot->Release();
  344. }
  345. }
  346. /*===================================================================
  347. CreateDocumentTree
  348. Takes a path to be rooted at a node "pDocRoot", parses the path,
  349. and creates a node for each component of the path. Returns the
  350. leaf (Since the root is known) as its value.
  351. This function is called from contexts where part of the document
  352. tree may already exist, so EnumChildren is called and nodes are only
  353. created when a child does not exist. When a node exists, we merely
  354. descend into the tree.
  355. NOTE:
  356. The intermediate nodes are created with a CFileNode document
  357. implementation. The leaf node is not given a document provider
  358. - the caller must provide one.
  359. Parameters
  360. wchar_t * szDocPath path of the document
  361. IDebugApplication *pDocParent parent to attach the application tree to
  362. IDebugApplication **ppDocRoot returns root of document hierarchy
  363. IDebugApplication **ppDocLeaf returns document leaf node.
  364. wchar_t ** pwszLeaf name of the leaf node
  365. Returns
  366. HRESULT
  367. ===================================================================*/
  368. HRESULT CreateDocumentTree
  369. (
  370. wchar_t *wszDocPath,
  371. IDebugApplicationNode *pDocParent,
  372. IDebugApplicationNode **ppDocRoot,
  373. IDebugApplicationNode **ppDocLeaf,
  374. wchar_t **pwszLeaf
  375. )
  376. {
  377. HRESULT hr;
  378. BOOL fCreateOnly = FALSE; // Set to TRUE when there is no need to check for duplicate node
  379. *ppDocRoot = *ppDocLeaf = NULL;
  380. // Ignore initial delimiters
  381. while (wszDocPath[0] == '/')
  382. ++wszDocPath;
  383. // Now loop over every component in the path, adding a node for each
  384. while (wszDocPath != NULL)
  385. {
  386. // Get next path component
  387. *pwszLeaf = wszDocPath;
  388. wszDocPath = wcschr(wszDocPath, L'/');
  389. if (wszDocPath)
  390. *wszDocPath++ = L'\0';
  391. // Check to see if this component is already a child or not
  392. BOOL fNodeExists = FALSE;
  393. if (!fCreateOnly)
  394. {
  395. IEnumDebugApplicationNodes *pEnum;
  396. if (SUCCEEDED(pDocParent->EnumChildren(&pEnum)) && pEnum != NULL)
  397. {
  398. IDebugApplicationNode *pDocChild;
  399. while (!fNodeExists && pEnum->Next(1, &pDocChild, NULL) == S_OK)
  400. {
  401. BSTR bstrName = NULL;
  402. if (FAILED(hr = pDocChild->GetName(DOCUMENTNAMETYPE_APPNODE, &bstrName)))
  403. return hr;
  404. if (wcscmp(bstrName, *pwszLeaf) == 0)
  405. {
  406. // The name of this node is equal to the component. Instead of
  407. // creating a new node, descend into the tree.
  408. //
  409. fNodeExists = TRUE;
  410. *ppDocLeaf = pDocChild;
  411. // If '*ppDocRoot' hasn't been assigned to yet, this means that
  412. // this is the first node found (and hence the root of the tree)
  413. //
  414. if (*ppDocRoot == NULL)
  415. {
  416. *ppDocRoot = pDocChild;
  417. (*ppDocRoot)->AddRef();
  418. }
  419. // If this node is a CFileNode structure (we don't require it to be)
  420. // then increment its (recursive) containing document count.
  421. //
  422. IFileNode *pFileNode;
  423. if (SUCCEEDED(pDocChild->QueryInterface(IID_IFileNode, reinterpret_cast<void **>(&pFileNode))))
  424. {
  425. pFileNode->IncrementDocumentCount();
  426. pFileNode->Release();
  427. }
  428. }
  429. SysFreeString(bstrName);
  430. pDocChild->Release();
  431. }
  432. pEnum->Release();
  433. }
  434. }
  435. // Create a new node if the node was not found above. Also, at this point,
  436. // to save time, we always set "fCreateOnly" to TRUE because if we are
  437. // forced to create a node at this level, we will need to create nodes at
  438. // all other levels further down
  439. //
  440. if (!fNodeExists)
  441. {
  442. fCreateOnly = TRUE;
  443. // Create the node
  444. if (FAILED(hr = g_pDebugApp->CreateApplicationNode(ppDocLeaf)))
  445. return hr;
  446. // Create a doc provider for the node - for intermediate nodes only
  447. if (wszDocPath != NULL) // intermediate node
  448. {
  449. CFileNode *pFileNode = new CFileNode;
  450. if (pFileNode == NULL ||
  451. FAILED(hr = pFileNode->Init(*pwszLeaf)) ||
  452. FAILED(hr = (*ppDocLeaf)->SetDocumentProvider(pFileNode)))
  453. {
  454. (*ppDocLeaf)->Release();
  455. return E_OUTOFMEMORY;
  456. }
  457. // New node, only one document (count started at 0, so this will set to 1)
  458. pFileNode->IncrementDocumentCount();
  459. // SetDocumentProvider() AddRef'ed
  460. pFileNode->Release();
  461. }
  462. // If '*ppDocRoot' hasn't been assigned to yet, this means that
  463. // this is the first node created (and hence the root of the tree)
  464. //
  465. if (*ppDocRoot == NULL)
  466. {
  467. *ppDocRoot = *ppDocLeaf;
  468. (*ppDocRoot)->AddRef();
  469. }
  470. // Attach the node
  471. if (FAILED(hr = (*ppDocLeaf)->Attach(pDocParent)))
  472. return hr;
  473. }
  474. // Descend
  475. pDocParent = *ppDocLeaf;
  476. }
  477. if (*ppDocLeaf)
  478. (*ppDocLeaf)->AddRef();
  479. return S_OK;
  480. }
  481. /*===================================================================
  482. Debugger
  483. The purpose of this thread is to create an execution environment for
  484. the Process Debug Manager (PDM). There is only one PDM per process,
  485. and this does not really fit in other threads, so we dedicate a thread to this.
  486. Parameters:
  487. LPVOID params
  488. Points to a BOOL* which will be set to 1 when
  489. this thread is completely initialized.
  490. Returns:
  491. 0
  492. ===================================================================*/
  493. void __cdecl Debugger(void *pvInit)
  494. {
  495. HRESULT hr;
  496. if (FAILED(hr = CoInitializeEx(NULL, COINIT_MULTITHREADED)))
  497. {
  498. // Bug 87857: if we get E_INVALIDARG, we need to do a CoUninitialize
  499. if (hr == E_INVALIDARG)
  500. CoUninitialize();
  501. *static_cast<BOOL *>(pvInit) = TRUE;
  502. return;
  503. }
  504. if (FAILED(CoCreateInstance(
  505. CLSID_ProcessDebugManager,
  506. NULL,
  507. CLSCTX_INPROC_SERVER,
  508. IID_IProcessDebugManager,
  509. reinterpret_cast<void **>(&g_pPDM))))
  510. {
  511. *static_cast<BOOL *>(pvInit) = TRUE;
  512. CoUninitialize();
  513. return;
  514. }
  515. *static_cast<BOOL *>(pvInit) = TRUE;
  516. while (TRUE)
  517. {
  518. DWORD dwRet = MsgWaitForMultipleObjects(1,
  519. &g_hPDMTermEvent,
  520. FALSE,
  521. INFINITE,
  522. QS_ALLINPUT);
  523. if (dwRet == WAIT_OBJECT_0)
  524. break;
  525. MSG msg;
  526. while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
  527. DispatchMessage(&msg);
  528. }
  529. g_pPDM->Release();
  530. CoUninitialize();
  531. g_pPDM = NULL; // indication that the thread is gone
  532. }
  533. /*===================================================================
  534. HRESULT StartPDM()
  535. kick off the PDM thread
  536. ===================================================================*/
  537. HRESULT StartPDM()
  538. {
  539. BOOL fStarted = FALSE;
  540. g_hPDMTermEvent = IIS_CREATE_EVENT(
  541. "g_hPDMTermEvent",
  542. &g_hPDMTermEvent,
  543. TRUE,
  544. FALSE
  545. );
  546. if( g_hPDMTermEvent == NULL )
  547. return E_FAIL;
  548. _beginthread(Debugger, 0, &fStarted);
  549. while (!fStarted)
  550. Sleep(100);
  551. if (g_pPDM == NULL) // could not create the PDM for some reason
  552. {
  553. CloseHandle(g_hPDMTermEvent);
  554. g_hPDMTermEvent = NULL;
  555. return E_FAIL;
  556. }
  557. return S_OK;
  558. }
  559. /*===================================================================
  560. HRESULT InitDebuggingAndCreateActivity
  561. Initialize everything we need for debugging
  562. NOTE: The long name here is meant to emphasize the different
  563. behaviors between Init & UnInit. Namely, the creation of
  564. the viper activity along with everything else.
  565. ===================================================================*/
  566. HRESULT InitDebuggingAndCreateActivity
  567. (
  568. CIsapiReqInfo *pIReq
  569. )
  570. {
  571. HRESULT hr;
  572. // Start the PDM
  573. if (FAILED(hr = StartPDM()))
  574. return hr;
  575. Assert (g_pPDM); // StartPDM succeeds ==> g_pPDM <> NULL
  576. ErrInitCriticalSection(&g_csDebugLock, hr);
  577. if (FAILED(hr))
  578. return hr;
  579. // Create the debug application & give it a name
  580. if (FAILED(hr = g_pPDM->CreateApplication(&g_pDebugApp)))
  581. goto LErrorCleanup;
  582. // WinSE 23918: tripple buffer size for friendly app names
  583. wchar_t wszDebugAppName[180];
  584. wcscpy(wszDebugAppName, L"Microsoft Active Server Pages"); // DO NOT LOCALIZE THIS STRING
  585. if (g_fOOP) {
  586. // Bug 154300: If a friendly app. name exists, use it along with the PID for
  587. // WAM identification.
  588. // WinSE 23918: avoid buffer overrun. use (..., pid) when friendly app name
  589. // is too long (about 120 chars or more). use(?, pid) when
  590. // failed to read friendly name. use (-, pid) when szAppMDPath
  591. // is empty. We may also return (, pid) when the app name
  592. // is set to empty string.
  593. //
  594. // Declare some temporaries
  595. //
  596. DWORD dwApplMDPathLen;
  597. DWORD dwRequiredBuffer = 0;
  598. DWORD cchPrefix = wcslen(wszDebugAppName);
  599. wchar_t *pFriendlyAppName = wszDebugAppName + cchPrefix;
  600. *pFriendlyAppName++ = ' ';
  601. *pFriendlyAppName++ = '(';
  602. TCHAR *szApplMDPath = pIReq->QueryPszApplnMDPath();
  603. // get friendly name from metabase
  604. hr = pIReq->GetAspMDData(
  605. szApplMDPath,
  606. MD_APP_FRIENDLY_NAME,
  607. METADATA_INHERIT,
  608. ASP_MD_UT_APP,
  609. STRING_METADATA,
  610. sizeof(wszDebugAppName) - (cchPrefix+20)*sizeof(wchar_t),
  611. 0,
  612. (BYTE*)pFriendlyAppName,
  613. &dwRequiredBuffer);
  614. if (hr == RETURNCODETOHRESULT(ERROR_INSUFFICIENT_BUFFER))
  615. {
  616. wcscpy(pFriendlyAppName, L"..."); // friendly app name too long
  617. }
  618. else if (FAILED(hr))
  619. {
  620. wcscpy(pFriendlyAppName, L"?"); // can't read friendly app name
  621. }
  622. pFriendlyAppName += wcslen(pFriendlyAppName);
  623. // append process id
  624. *pFriendlyAppName++ = ',';
  625. *pFriendlyAppName++ = ' ';
  626. _itow(GetCurrentProcessId(), pFriendlyAppName, 10);
  627. wcscat(pFriendlyAppName, L")");
  628. }
  629. if (FAILED(hr = g_pDebugApp->SetName(wszDebugAppName)))
  630. goto LErrorCleanup;
  631. if (FAILED(hr = g_pPDM->AddApplication(g_pDebugApp, &g_dwDenaliAppCookie)))
  632. goto LErrorCleanup;
  633. if (FAILED(hr = g_pDebugApp->GetRootNode(&g_pDebugAppRoot)))
  634. goto LErrorCleanup;
  635. // Create Viper Activity for debugging
  636. g_pDebugActivity = new CViperActivity;
  637. if (g_pDebugActivity == NULL) {
  638. hr = E_OUTOFMEMORY;
  639. goto LErrorCleanup;
  640. }
  641. if (FAILED(hr = g_pDebugActivity->Init()))
  642. goto LErrorCleanup;
  643. // Init the hash table used for Keeping track of virtual server roots
  644. if (FAILED(hr = g_HashMDPath2DebugRoot.Init()))
  645. goto LErrorCleanup;
  646. // Create the array for passing data to debug thread
  647. if ((g_prgThreadCallArgs = new vector<DebugThreadCallArgs>) == NULL) {
  648. hr = E_OUTOFMEMORY;
  649. goto LErrorCleanup;
  650. }
  651. return S_OK;
  652. LErrorCleanup:
  653. // Clean up some globals (some thing may be NULL and some not)
  654. if (g_pDebugAppRoot) {
  655. g_pDebugAppRoot->Release();
  656. g_pDebugAppRoot = NULL;
  657. }
  658. if (g_pDebugApp) {
  659. g_pDebugApp->Release();
  660. g_pDebugApp = NULL;
  661. }
  662. if (g_pDebugActivity) {
  663. delete g_pDebugActivity;
  664. g_pDebugActivity = NULL;
  665. }
  666. // Kill PDM thread if we started it up.
  667. if (g_pPDM) {
  668. SetEvent(g_hPDMTermEvent);
  669. while (g_pPDM)
  670. Sleep(100);
  671. CloseHandle(g_hPDMTermEvent);
  672. g_pPDM = NULL;
  673. }
  674. return hr;
  675. }
  676. /*===================================================================
  677. UnInitDebugging
  678. Uninitialize debugging
  679. NOTE: WE DO NOT RELEASE THE VIPER DEBUG ACTIVITY.
  680. (EVEN THOUGH INIT CREATES IT)
  681. THIS IS BECAUSE UNINIT MUST BE INVOKED WHILE SCRIPTS ON THE
  682. ACTIVITY ARE STILL RUNNING!
  683. ===================================================================*/
  684. HRESULT UnInitDebugging()
  685. {
  686. // Clear and UnInit the hash tables (containing the application nodes)
  687. CDebugNodeElem *pNukeDebugNode = static_cast<CDebugNodeElem *>(g_HashMDPath2DebugRoot.Head());
  688. while (pNukeDebugNode != NULL)
  689. {
  690. CDebugNodeElem *pNext = static_cast<CDebugNodeElem *>(pNukeDebugNode->m_pNext);
  691. pNukeDebugNode->m_pServerRoot->Detach();
  692. pNukeDebugNode->m_pServerRoot->Close();
  693. pNukeDebugNode->m_pServerRoot->Release();
  694. delete pNukeDebugNode;
  695. pNukeDebugNode = pNext;
  696. }
  697. g_HashMDPath2DebugRoot.UnInit();
  698. DeleteCriticalSection(&g_csDebugLock);
  699. // Unlink the top node
  700. if (g_pDebugAppRoot)
  701. {
  702. g_pDebugAppRoot->Detach();
  703. g_pDebugAppRoot->Close();
  704. g_pDebugAppRoot->Release();
  705. }
  706. // Delete the application
  707. if (g_pDebugApp)
  708. {
  709. Assert (g_pPDM != NULL);
  710. // EXPLICITLY ignore failure result here:
  711. // if Init() failed earlier, then RemoveApplication will fail here.
  712. g_pPDM->RemoveApplication(g_dwDenaliAppCookie);
  713. g_pDebugApp->Close();
  714. g_pDebugApp->Release();
  715. g_pDebugApp = NULL;
  716. }
  717. // Tell the PDM to suicide
  718. if (g_pPDM)
  719. {
  720. SetEvent(g_hPDMTermEvent);
  721. while (g_pPDM)
  722. Sleep(100);
  723. CloseHandle(g_hPDMTermEvent);
  724. }
  725. // delete the argument buffer
  726. delete g_prgThreadCallArgs;
  727. return S_OK;
  728. }
  729. /*===================================================================
  730. GetServerDebugRoot
  731. Each virtual server has its own root in the application tree.
  732. (i.e. the tree looks like
  733. Microsoft ASP
  734. <Virtual Server 1 Name>
  735. <Denali Application Name>
  736. <Files>
  737. <Virtual Server 2 Name>
  738. <Denali Application>
  739. ...
  740. Since there may be multiple applications per each server, the
  741. server nodes are managed at one central location (here) so that
  742. new applications get added to the correct nodes.
  743. ===================================================================*/
  744. HRESULT GetServerDebugRoot
  745. (
  746. CIsapiReqInfo *pIReq,
  747. IDebugApplicationNode **ppDebugRoot
  748. )
  749. {
  750. HRESULT hr = E_FAIL;
  751. STACK_BUFFER( tempMDData, 2048 );
  752. *ppDebugRoot = NULL;
  753. // Get the metabase path for this virtual server from the CIsapiReqInfo
  754. DWORD dwInstanceMDPathLen;
  755. char *szInstanceMDPath;
  756. STACK_BUFFER( instPathBuf, 128 );
  757. if (!SERVER_GET(pIReq, "INSTANCE_META_PATH", &instPathBuf, &dwInstanceMDPathLen))
  758. return HRESULT_FROM_WIN32(GetLastError());
  759. szInstanceMDPath = (char *)instPathBuf.QueryPtr();
  760. // See if we already have a node for this path - If not then create it and add to hash table
  761. EnterCriticalSection(&g_csDebugLock);
  762. CDebugNodeElem *pDebugNode = static_cast<CDebugNodeElem *>(g_HashMDPath2DebugRoot.FindElem(szInstanceMDPath, dwInstanceMDPathLen - 1));
  763. if (!pDebugNode)
  764. {
  765. // Node does not exist, so create a new application node.
  766. pDebugNode = new CDebugNodeElem;
  767. if (pDebugNode == NULL)
  768. {
  769. hr = E_OUTOFMEMORY;
  770. goto LExit;
  771. }
  772. if (FAILED(hr = pDebugNode->Init(szInstanceMDPath, dwInstanceMDPathLen - 1)))
  773. goto LExit;
  774. // Look up server name in metabase.
  775. BYTE *prgbData = (BYTE *)tempMDData.QueryPtr();
  776. DWORD dwRequiredBuffer = 0;
  777. hr = pIReq->GetAspMDDataA(
  778. szInstanceMDPath,
  779. MD_SERVER_COMMENT,
  780. METADATA_INHERIT,
  781. IIS_MD_UT_SERVER,
  782. STRING_METADATA,
  783. tempMDData.QuerySize(),
  784. 0,
  785. prgbData,
  786. &dwRequiredBuffer);
  787. if (hr == RETURNCODETOHRESULT(ERROR_INSUFFICIENT_BUFFER)) {
  788. if (tempMDData.Resize(dwRequiredBuffer) == FALSE) {
  789. hr = E_OUTOFMEMORY;
  790. }
  791. else {
  792. prgbData = reinterpret_cast<BYTE *>(tempMDData.QueryPtr());
  793. hr = pIReq->GetAspMDDataA(
  794. szInstanceMDPath,
  795. MD_SERVER_COMMENT,
  796. METADATA_INHERIT,
  797. IIS_MD_UT_SERVER,
  798. STRING_METADATA,
  799. dwRequiredBuffer,
  800. 0,
  801. prgbData,
  802. &dwRequiredBuffer);
  803. }
  804. }
  805. if (FAILED(hr))
  806. {
  807. // ServerComment does not exist, so construct using server name and port
  808. STACK_BUFFER( serverNameBuff, 16 );
  809. DWORD cbServerName;
  810. STACK_BUFFER( serverPortBuff, 10 );
  811. DWORD cbServerPort;
  812. STACK_BUFFER( debugNodeBuff, 30 );
  813. if (!SERVER_GET(pIReq, "LOCAL_ADDR", &serverNameBuff, &cbServerName)
  814. || !SERVER_GET(pIReq, "SERVER_PORT", &serverPortBuff, &cbServerPort)) {
  815. hr = E_FAIL;
  816. goto LExit;
  817. }
  818. char *szServerName = (char *)serverNameBuff.QueryPtr();
  819. char *szServerPort = (char*)serverPortBuff.QueryPtr();
  820. // resize the debugNodeBuff to hold <serverIP>:<port>'\0'.
  821. if (!debugNodeBuff.Resize(cbServerName + cbServerPort + 2)) {
  822. hr = E_OUTOFMEMORY;
  823. goto LExit;
  824. }
  825. // Syntax is <serverIP:port>
  826. char *szDebugNode = (char *)debugNodeBuff.QueryPtr();
  827. strcpyExA(strcpyExA(strcpyExA(szDebugNode, szServerName), ":"), szServerPort);
  828. // Convert to Wide Char
  829. hr = MultiByteToWideChar(CP_ACP, 0, szDebugNode, -1, reinterpret_cast<wchar_t *>(prgbData), tempMDData.QuerySize() / 2);
  830. if (FAILED(hr))
  831. goto LExit;
  832. }
  833. // We've got the metadata (ServerComment), create a debug node with this name
  834. IDebugApplicationNode *pServerRoot;
  835. if (FAILED(hr = g_pDebugApp->CreateApplicationNode(&pServerRoot)))
  836. goto LExit;
  837. // Create a doc provider for the node
  838. CFileNode *pFileNode = new CFileNode;
  839. if (pFileNode == NULL)
  840. {
  841. hr = E_OUTOFMEMORY;
  842. goto LExit;
  843. }
  844. if (FAILED(hr = pFileNode->Init(reinterpret_cast<wchar_t *>(prgbData))))
  845. goto LExit;
  846. if (FAILED(hr = pServerRoot->SetDocumentProvider(pFileNode)))
  847. goto LExit;
  848. // pFileNode has been AddRef'ed and we don't need it now.
  849. pFileNode->Release();
  850. // Attach to the UI
  851. if (FAILED(pServerRoot->Attach(g_pDebugAppRoot)))
  852. goto LExit;
  853. // OK, Now add this item to the hashtable (this eats the reference from creation)
  854. pDebugNode->m_pServerRoot = pServerRoot;
  855. g_HashMDPath2DebugRoot.AddElem(pDebugNode);
  856. }
  857. *ppDebugRoot = pDebugNode->m_pServerRoot;
  858. (*ppDebugRoot)->AddRef();
  859. hr = S_OK;
  860. LExit:
  861. LeaveCriticalSection(&g_csDebugLock);
  862. return hr;
  863. }
  864. /*===================================================================
  865. C F i l e N o d e
  866. Implementation of CFileNode - trivial class
  867. ===================================================================*/
  868. const GUID IID_IFileNode =
  869. { 0x41047bd2, 0xfe1e, 0x11d0, { 0x8f, 0x3f, 0x0, 0xc0, 0x4f, 0xc3, 0x4d, 0xcc } };
  870. CFileNode::CFileNode() : m_cRefs(1), m_cDocuments(0), m_wszName(NULL) {}
  871. CFileNode::~CFileNode() { delete[] m_wszName; }
  872. HRESULT
  873. CFileNode::Init(wchar_t *wszName)
  874. {
  875. if ((m_wszName = new wchar_t [wcslen(wszName) + 1]) == NULL)
  876. return E_OUTOFMEMORY;
  877. wcscpy(m_wszName, wszName);
  878. return S_OK;
  879. }
  880. HRESULT
  881. CFileNode::QueryInterface(const GUID &uidInterface, void **ppvObj)
  882. {
  883. if (uidInterface == IID_IUnknown ||
  884. uidInterface == IID_IDebugDocumentProvider ||
  885. uidInterface == IID_IFileNode)
  886. {
  887. *ppvObj = this;
  888. AddRef();
  889. return S_OK;
  890. }
  891. else
  892. return E_NOINTERFACE;
  893. }
  894. ULONG
  895. CFileNode::AddRef()
  896. {
  897. InterlockedIncrement(reinterpret_cast<long *>(&m_cRefs));
  898. return m_cRefs;
  899. }
  900. ULONG
  901. CFileNode::Release()
  902. {
  903. if (InterlockedDecrement(reinterpret_cast<long *>(&m_cRefs)) == 0)
  904. {
  905. delete this;
  906. return 0;
  907. }
  908. return m_cRefs;
  909. }
  910. HRESULT
  911. CFileNode::GetDocument(IDebugDocument **ppDebugDoc)
  912. {
  913. return QueryInterface(IID_IDebugDocument, reinterpret_cast<void **>(ppDebugDoc));
  914. }
  915. HRESULT
  916. CFileNode::GetName(DOCUMENTNAMETYPE, BSTR *pbstrName)
  917. {
  918. return ((*pbstrName = SysAllocString(m_wszName)) == NULL)? E_OUTOFMEMORY : S_OK;
  919. }