home *** CD-ROM | disk | FTP | other *** search
/ io Programmo 40 / IOPROG_40.ISO / SOFT / NETFrameworkSDK.exe / comsdk.cab / samples1.exe / Debugger / dshell.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2000-06-23  |  210.6 KB  |  8,061 lines

  1. /* ------------------------------------------------------------------------- *
  2.  * debug\comshell.cpp: com debugger shell functions
  3.  * ------------------------------------------------------------------------- */
  4.  
  5. #include "stdafx.h"
  6.  
  7. #include "dshell.h"
  8.  
  9. #ifdef _INTERNAL_DEBUG_SUPPORT_
  10. #include "__file__.ver"
  11. #endif
  12.  
  13. // Poor-man's import of System.Object. Can't import mscorlib.tlb since
  14. // it hasn't been built yet.
  15. static const GUID IID_Object = { 0x98417C7D, 0x32E8, 0x3FA0, { 0xA5, 0x4B, 0x0F, 0x0B, 0x2E, 0xFB, 0xE9, 0x1F }};
  16.  
  17. struct _Object : IDispatch
  18. {
  19.     virtual HRESULT __stdcall get_ToString(BSTR *pBstr) = 0;        
  20.     virtual HRESULT __stdcall Equals() = 0;
  21.     virtual HRESULT __stdcall GetHashCode() = 0;
  22.     virtual HRESULT __stdcall GetType() = 0;
  23. };
  24.  
  25. /* ------------------------------------------------------------------------- *
  26.  * Globals
  27.  * ------------------------------------------------------------------------- */
  28.  
  29. DebuggerShell         *g_pShell = NULL;
  30.  
  31. #if DOSPEW
  32. #define SPEW(s) s
  33. #else
  34. #define SPEW(s)
  35. #endif
  36.  
  37. WCHAR *FindSep(                         // Pointer to separator or null.
  38.     const WCHAR *szPath)                // The path to look in.
  39. {
  40.     WCHAR *ptr = wcsrchr(szPath, L'.');
  41.     if (ptr && ptr - 1 >= szPath && *(ptr - 1) == L'.')
  42.         --ptr;
  43.     return ptr;
  44. }
  45.  
  46. ICorDebugController *GetControllerInterface(ICorDebugAppDomain *pAppDomain)
  47. {
  48.     ICorDebugProcess *pProcess = NULL;
  49.     ICorDebugController *pController = NULL;
  50.     HRESULT hr = S_OK;
  51.  
  52.     hr = pAppDomain->GetProcess(&pProcess);
  53.     if (FAILED(hr))
  54.         return pController;
  55.  
  56.     hr = pProcess->QueryInterface(IID_ICorDebugController,
  57.                                   (void**)&pController);
  58.     if (FAILED(hr))
  59.     {
  60.         pProcess->Release();
  61.     }
  62.  
  63.     _ASSERTE(pController != NULL); 
  64.     return pController;
  65.  /*  @todo APPD Leave this infrastructure in place for later --MiPanitz
  66.     if (g_pShell->m_rgfActiveModes & DSM_SHOW_SELECTIVE_APPDOMAIN)
  67.     {
  68.         hr = pAppDomain->QueryInterface(IID_ICorDebugController,
  69.                                         (void**)&pController);
  70.         return pController;
  71.     }
  72.     else
  73.     {
  74.         hr = pAppDomain->GetProcess(&pProcess);
  75.         if (FAILED(hr))
  76.             return pController;
  77.  
  78.         hr = pProcess->QueryInterface(IID_ICorDebugController,
  79.                                       (void**)&pController);
  80.         if (FAILED(hr))
  81.         {
  82.             pProcess->Release();
  83.         }
  84.         
  85.         _ASSERTE(pController != NULL); 
  86.         return pController;
  87.     }
  88. */
  89. }
  90.  
  91. HRESULT DebuggerCallback::CreateProcess(ICorDebugProcess *pProcess)
  92. {
  93.     DWORD pid = 0;
  94.     
  95.     SPEW(fprintf(stderr, "[%d] DC::CreateProcess.\n", GetCurrentThreadId()));
  96.  
  97.     pProcess->GetID(&pid);
  98.     g_pShell->Write(L"Process %d/0x%x created.\n", pid, pid);
  99.     g_pShell->SetTargetProcess(pProcess);
  100.  
  101.     SPEW(fprintf(stderr, "[%d] DC::CP: creating process.\n", GetCurrentThreadId()));
  102.     SPEW(fprintf(stderr, "[%d] DC::CP: returning.\n", GetCurrentThreadId()));
  103.  
  104.     // Also initialize the source file search path 
  105.     g_pShell->m_FPCache.Init ();
  106.  
  107.  
  108.     g_pShell->m_gotFirstThread = false;
  109.  
  110.     g_pShell->Continue(pProcess, NULL);
  111.  
  112.     return (S_OK);
  113. }
  114.  
  115. HRESULT DebuggerCallback::ExitProcess(ICorDebugProcess *pProcess)
  116. {
  117.     SPEW(fprintf(stderr, "[%d] DC::ExitProcess.\n", GetCurrentThreadId()));
  118.  
  119.     g_pShell->Write(L"Process exited.\n");
  120.  
  121.     if (g_pShell->m_targetProcess == pProcess)
  122.         g_pShell->SetTargetProcess(NULL);
  123.  
  124.     g_pShell->Stop(NULL, NULL);
  125.  
  126.     SPEW(fprintf(stderr, "[%d] DC::EP: returning.\n", GetCurrentThreadId()));
  127.     return (S_OK);
  128. }
  129.  
  130.  
  131. //  @mfunc BOOL|DebuggerShell|SkipProlog|Determines if
  132. //    the debuggee is current inside of either a prolog or
  133. //    interceptor (eg, class initializer), and if we don't
  134. //    want to be, then it steps us over or out of (respectively)
  135. //    the code region.
  136. //    @rdesc returns TRUE if we are in a prolog||interceptor,
  137. //        and we've stepped over XOR out of that region.
  138. //        Otherwise, returns FALSE
  139. BOOL DebuggerShell::SkipProlog( ICorDebugAppDomain *pAD,
  140.                                 ICorDebugThread *thread)
  141. {
  142.     ICorDebugFrame *pFrame = NULL;
  143.     ICorDebugILFrame *pilFrame = NULL;
  144.     ULONG32 ilOff = 0;
  145.     CorDebugMappingResult mapping;
  146.     bool fStepOver = false;
  147.  
  148.     ICorDebugChain *chain = NULL;
  149.     CorDebugChainReason reason;
  150.     bool fStepOutOf = false;
  151.         
  152.     ICorDebugStepper *pStepper = NULL;
  153.     // If we're in the prolog or interceptor,
  154.     // but the user doesn't want to see it, create
  155.     // a stepper to step over the prolog
  156.     if (! (m_rgfActiveModes & DSM_UNMAPPED_STOP_PROLOG
  157.          ||m_rgfActiveModes & DSM_UNMAPPED_STOP_ALL) )
  158.     {
  159.         SPEW(fprintf(stderr, "DC::CreateThread: We're not interested in prologs\n"));
  160.  
  161.         if (FAILED(thread->GetActiveFrame( &pFrame ) ) ||
  162.             (pFrame == NULL) ||
  163.             FAILED(pFrame->QueryInterface(IID_ICorDebugILFrame,
  164.                                           (void**)&pilFrame)) ||
  165.             FAILED(pilFrame->GetIP( &ilOff, &mapping )) )
  166.         {
  167.             Write(L"Unable to  determine existence of prolog, if any\n");
  168.             mapping = (CorDebugMappingResult)~MAPPING_PROLOG;
  169.         }
  170.  
  171.         if (mapping & MAPPING_PROLOG)
  172.         {
  173.             fStepOver = true;
  174.         }
  175.     }
  176.  
  177.     // Are we in an interceptor?
  178.     if (FAILED(thread->GetActiveChain( &chain ) ) )
  179.     {
  180.         Write( L"Unable to obtain active chain!\n" );
  181.         goto LExit;
  182.     }
  183.     
  184.     if ( FAILED( chain->GetReason( &reason)) )
  185.     {
  186.         Write( L"Unable to query current chain!\n" );
  187.         RELEASE( chain );
  188.         chain = NULL;
  189.         goto LExit;
  190.     }
  191.     RELEASE( chain );
  192.     chain = NULL;
  193.  
  194.     // If there's any interesting reason & we've said stop on everything, then
  195.     // don't step out
  196.     // Otherwise, as long as at least one reason has 
  197.     // been flagged by the user as uninteresting, and we happen to be in such
  198.     // an uninteresting frame, then we should step out.
  199.     if (
  200.         !( (reason &(CHAIN_CLASS_INIT|CHAIN_SECURITY|
  201.                     CHAIN_EXCEPTION_FILTER|CHAIN_CONTEXT_POLICY
  202.                     |CHAIN_INTERCEPTION))&&
  203.             (m_rgfActiveModes & DSM_INTERCEPT_STOP_ALL))
  204.         &&
  205.         (((reason & CHAIN_CLASS_INIT) && 
  206.             !(m_rgfActiveModes & DSM_INTERCEPT_STOP_CLASS_INIT))
  207.         ||((reason & CHAIN_SECURITY) && 
  208.             !(m_rgfActiveModes & DSM_INTERCEPT_STOP_SECURITY)) 
  209.         ||((reason & CHAIN_EXCEPTION_FILTER) && 
  210.             !(m_rgfActiveModes & DSM_INTERCEPT_STOP_EXCEPTION_FILTER))
  211.         ||((reason & CHAIN_CONTEXT_POLICY) && 
  212.             !(m_rgfActiveModes & DSM_INTERCEPT_STOP_CONTEXT_POLICY)) 
  213.         ||((reason & CHAIN_INTERCEPTION) && 
  214.             !(m_rgfActiveModes & DSM_INTERCEPT_STOP_INTERCEPTION)))
  215.        )
  216.     {
  217.         fStepOutOf = true;
  218.     }
  219.     
  220.     if ( fStepOutOf || fStepOver )
  221.     {
  222.         if ( FAILED(thread->CreateStepper( &pStepper )) ||
  223.              FAILED(pStepper->SetUnmappedStopMask(ComputeStopMask())) ||
  224.              FAILED(pStepper->SetInterceptMask(ComputeInterceptMask())))
  225.         {
  226.             Write( L"Unable to step around special code!\n");
  227.             goto LExit;
  228.         }
  229.  
  230.         if ( fStepOutOf )
  231.         {
  232.             if (FAILED(pStepper->StepOut()) )
  233.             {
  234.                 Write( L"Unable to step out of interceptor\n" );
  235.                 goto LExit;
  236.             }
  237.         }
  238.         else if ( fStepOver && FAILED(pStepper->Step(false)))
  239.         {
  240.             Write( L"Unable to step over prolog,epilog,etc\n" );
  241.             goto LExit;
  242.         }
  243.         
  244.         StepStart(thread, pStepper);            
  245.         m_showSource = true;
  246.  
  247.         ICorDebugController *pController = GetControllerInterface(pAD);
  248.         Continue(pController, thread);
  249.          
  250.         if (pController!=NULL)
  251.             pController->Release();
  252.     }
  253. LExit:
  254.     if (pFrame != NULL )
  255.     {
  256.         RELEASE( pFrame );
  257.         pFrame = NULL;
  258.     }
  259.  
  260.     if (pilFrame != NULL )
  261.     {
  262.         RELEASE( pilFrame );
  263.         pilFrame = NULL;
  264.     }
  265.  
  266.     if ( chain != NULL)
  267.     {
  268.         RELEASE( chain );
  269.         chain = NULL;
  270.     }
  271.     
  272.     return (fStepOver || fStepOutOf)?(TRUE):(FALSE);
  273. }
  274.  
  275. enum printType
  276. {
  277.     PT_CREATED,
  278.     PT_EXITED,
  279.     PT_IN,
  280.     PT_NONE
  281. };
  282.  
  283. static void _printAppDomain(ICorDebugAppDomain *pAppDomain,
  284.                             printType pt)
  285. {
  286.     ULONG32 id;
  287.  
  288.     HRESULT hr = pAppDomain->GetID(&id);
  289.     _ASSERTE(SUCCEEDED(hr));
  290.     
  291.     WCHAR buff[256];
  292.     ULONG32 s;
  293.     WCHAR *defaultName = L"<Unknown appdomain>";
  294.     WCHAR *name = defaultName;
  295.  
  296.     hr = pAppDomain->GetName(256, &s, buff);
  297.  
  298.     if (SUCCEEDED(hr))
  299.         name = buff;
  300.  
  301.     if (pt == PT_IN)
  302.         g_pShell->Write(L"\tin appdomain #%d, %s\n", id, name);
  303.     else if (pt == PT_CREATED)
  304.         g_pShell->Write(L"Appdomain #%d, %s -- Created\n", id, name);
  305.     else if (pt == PT_EXITED)
  306.         g_pShell->Write(L"Appdomain #%d, %s -- Exited\n", id, name);
  307.     else
  308.         g_pShell->Write(L"Appdomain #%d, %s\n", id, name);
  309. }
  310.  
  311. static void _printAssembly(ICorDebugAssembly *pAssembly,
  312.                            printType pt)
  313. {
  314.     WCHAR buff[256];
  315.     ULONG32 s;
  316.     WCHAR *defaultName = L"<Unknown assembly>";
  317.     WCHAR *name = defaultName;
  318.  
  319.     HRESULT hr = pAssembly->GetName(256, &s, buff);
  320.  
  321.     if (SUCCEEDED(hr))
  322.         name = buff;
  323.  
  324.     if (pt == PT_IN)
  325.         g_pShell->Write(L"\tin assembly 0x%08x, %s\n", pAssembly, name);
  326.     else if (pt == PT_CREATED)
  327.         g_pShell->Write(L"Assembly 0x%08x, %s -- Loaded\n", pAssembly, name);
  328.     else if (pt == PT_EXITED)
  329.         g_pShell->Write(L"Assembly 0x%08x, %s -- Unloaded\n", pAssembly, name);
  330.     else
  331.         g_pShell->Write(L"Assembly 0x%08x, %s\n", pAssembly, name);
  332. }
  333.  
  334. static void _printModule(ICorDebugModule *pModule,
  335.                          printType pt)
  336. {
  337.     WCHAR buff[256];
  338.     ULONG32 s;
  339.     WCHAR *defaultName = L"<Unknown module>";
  340.     WCHAR *name = defaultName;
  341.  
  342.     HRESULT hr = pModule->GetName(256, &s, buff);
  343.  
  344.     if (SUCCEEDED(hr))
  345.         name = buff;
  346.  
  347.     BOOL isDynamic = FALSE;
  348.  
  349.     hr = pModule->IsDynamic(&isDynamic);
  350.     _ASSERTE(SUCCEEDED(hr));
  351.  
  352.     WCHAR *mt;
  353.  
  354.     if (isDynamic)
  355.         mt = L"Dynamic Module";
  356.     else
  357.         mt = L"Module";
  358.     
  359.     if (pt == PT_IN)
  360.         g_pShell->Write(L"\tin %s 0x%08x, %s\n", mt, pModule, name);
  361.     else if (pt == PT_CREATED)
  362.         g_pShell->Write(L"%s 0x%08x, %s -- Loaded\n", mt, pModule, name);
  363.     else if (pt == PT_EXITED)
  364.         g_pShell->Write(L"%s 0x%08x, %s -- Unloaded\n", mt, pModule, name);
  365.     else
  366.     {
  367.         ICorDebugAppDomain *pAD;
  368.         ICorDebugAssembly *pAS;
  369.  
  370.         hr = pModule->GetAssembly(&pAS);
  371.         _ASSERTE(SUCCEEDED(hr));
  372.  
  373.         hr = pAS->GetAppDomain(&pAD);
  374.         _ASSERTE(SUCCEEDED(hr));
  375.  
  376.         ULONG32 adId;
  377.         hr = pAD->GetID(&adId);
  378.         _ASSERTE(SUCCEEDED(hr));
  379.         
  380.         g_pShell->Write(L"%s 0x%08x, %s -- AD #%d\n", mt, pModule, name,
  381.                         adId);
  382.     }
  383. }
  384.  
  385. /*
  386.  * CreateAppDomain is called when an app domain is created.
  387.  */
  388. HRESULT DebuggerCallback::CreateAppDomain(ICorDebugProcess *pProcess,
  389.                                           ICorDebugAppDomain *pAppDomain)
  390. {
  391.     SPEW(fprintf(stderr, "[%d] DC::CreateAppDomain.\n", GetCurrentThreadId()));
  392.  
  393.     if (g_pShell->m_rgfActiveModes & DSM_SHOW_APP_DOMAIN_ASSEMBLY_LOADS)
  394.         _printAppDomain(pAppDomain, PT_CREATED);
  395.  
  396.     // Attach to this app domain
  397.     if (!(g_pShell->m_rgfActiveModes & 
  398.           DSM_SHOW_SELECTIVE_APPDOMAIN))
  399.     {
  400.         pAppDomain->Attach();
  401.         g_pShell->Continue(pProcess, NULL);
  402.     }
  403.     else
  404.     {
  405.         // check if there are any more CreateAppDomain events in the queue. 
  406.         // if so, return (without sending Continue() to the left side) so that
  407.         // we can get the remaining callbacks for the appdomains. Once we have 
  408.         // emptied the queue, the user will decide which app domain to attach to.
  409.         BOOL fQueued;
  410.         pProcess->HasQueuedCallbacks (NULL, &fQueued);
  411.  
  412.         ICorDebugController *pController = GetControllerInterface(pAppDomain);
  413.  
  414.         if (fQueued == FALSE)
  415.         {
  416.             SetEvent (g_pShell->m_hProcessCreated);
  417.             g_pShell->Stop(pController, NULL);
  418.         }
  419.         else
  420.         {
  421.             g_pShell->Continue(pController,NULL);
  422.         }
  423.     }
  424.  
  425.     return S_OK;
  426. }
  427.  
  428. /*
  429.  * ExitAppDomain is called when an app domain exits.
  430.  */
  431. HRESULT DebuggerCallback::ExitAppDomain(ICorDebugProcess *pProcess,
  432.                                         ICorDebugAppDomain *pAppDomain)
  433. {
  434.     SPEW(fprintf(stderr, "[%d] DC::ExitAppDomain.\n", GetCurrentThreadId()));
  435.  
  436.     if (g_pShell->m_rgfActiveModes & DSM_SHOW_APP_DOMAIN_ASSEMBLY_LOADS)
  437.     {
  438.         _printAppDomain(pAppDomain, PT_EXITED);
  439.     }
  440.  
  441.     ICorDebugController *pController = GetControllerInterface(pAppDomain);
  442.  
  443.     g_pShell->Continue(pController, NULL);
  444.  
  445.     if (pController != NULL)
  446.         pController->Release();
  447.  
  448.     return S_OK;
  449. }
  450.  
  451.  
  452. /*
  453.  * LoadAssembly is called when a NGWS module is successfully
  454.  * loaded. 
  455.  */
  456. HRESULT DebuggerCallback::LoadAssembly(ICorDebugAppDomain *pAppDomain,
  457.                                        ICorDebugAssembly *pAssembly)
  458. {
  459.     SPEW(fprintf(stderr, "[%d] DC::LoadAssembly.\n", GetCurrentThreadId()));
  460.  
  461.     if (g_pShell->m_rgfActiveModes & DSM_SHOW_APP_DOMAIN_ASSEMBLY_LOADS)
  462.     {
  463.         _printAssembly(pAssembly, PT_CREATED);
  464.         _printAppDomain(pAppDomain, PT_IN);
  465.     }
  466.  
  467.     ICorDebugController *pController = GetControllerInterface(pAppDomain);
  468.  
  469.     g_pShell->Continue(pController, NULL);
  470.  
  471.     if (pController != NULL)
  472.         pController->Release();
  473.  
  474.     return S_OK;
  475. }
  476.  
  477. /*
  478.  * UnloadAssembly is called when a NGWS module (DLL) is unloaded. The module 
  479.  * should not be used after this point.
  480.  */
  481. HRESULT DebuggerCallback::UnloadAssembly(ICorDebugAppDomain *pAppDomain,
  482.                                          ICorDebugAssembly *pAssembly)
  483. {
  484.     SPEW(fprintf(stderr, "[%d] DC::UnloadAssembly.\n", GetCurrentThreadId()));
  485.  
  486.     if (g_pShell->m_rgfActiveModes & DSM_SHOW_APP_DOMAIN_ASSEMBLY_LOADS)
  487.     {
  488.         _printAssembly(pAssembly, PT_EXITED);
  489.     }
  490.  
  491.     ICorDebugController *pController = GetControllerInterface(pAppDomain);
  492.  
  493.     g_pShell->Continue(pController, NULL);
  494.  
  495.     if (pController != NULL)
  496.         pController->Release();
  497.  
  498.     return S_OK;
  499. }
  500.  
  501.  
  502. HRESULT DebuggerCallback::Breakpoint( ICorDebugAppDomain *pAppDomain,
  503.                     ICorDebugThread *pThread, 
  504.                     ICorDebugBreakpoint *pBreakpoint)
  505. {
  506.     SPEW(fprintf(stderr, "[%d] DC::Breakpoint.\n", GetCurrentThreadId()));
  507.  
  508.     ICorDebugProcess *pProcess;
  509.     pAppDomain->GetProcess(&pProcess);
  510.  
  511.     DebuggerBreakpoint *bp = g_pShell->m_breakpoints;
  512.  
  513.     while (bp && !bp->Match(pBreakpoint))
  514.         bp = bp->m_next;
  515.  
  516.     if (bp)
  517.     {
  518.         g_pShell->PrintThreadPrefix(pThread);
  519.         g_pShell->Write(L"break at ");
  520.         g_pShell->PrintBreakpoint(bp);
  521.     }
  522.     else
  523.     {
  524.         g_pShell->Write(L"Internal CORDBG error!  Please report to mailto:corbug.\n");
  525.         g_pShell->Write(L"Unknown breakpoint hit.  Continuing may produce unexpected results.\n");
  526.     }
  527.  
  528.     g_pShell->Stop(pProcess, pThread);
  529.  
  530.     return S_OK;
  531. }
  532.  
  533. const WCHAR *StepTypeToString( CorDebugStepReason reason )
  534. {
  535.     switch (reason)
  536.     {
  537.         case STEP_NORMAL:
  538.             return L"STEP_NORMAL";
  539.             break;
  540.         case STEP_RETURN:
  541.             return L"STEP_RETURN";
  542.             break;
  543.         case STEP_CALL:
  544.             return L"STEP_CALL";
  545.             break;
  546.         case STEP_EXCEPTION_FILTER:
  547.             return L"STEP_EXCEPTION_FILTER";
  548.             break;
  549.         case STEP_EXCEPTION_HANDLE:
  550.             return L"STEP_EXCEPTION_HANDLE";
  551.             break;
  552.         case STEP_INTERCEPT:
  553.             return L"STEP_INTERCEPT";
  554.             break;
  555.         case STEP_EXIT:
  556.             return L"STEP_EXIT";
  557.             break;
  558.         default:
  559.             _ASSERTE( !"StepTypeToString given unknown step type!" );
  560.             return NULL;
  561.             break;
  562.     }
  563. }
  564.  
  565. HRESULT DebuggerCallback::StepComplete( ICorDebugAppDomain *pAppDomain,
  566.                       ICorDebugThread *pThread,
  567.                       ICorDebugStepper *pStepper,
  568.                       CorDebugStepReason reason)
  569. {
  570.     SPEW(fprintf(stderr, "[%d] DC::StepComplete with reason %d.\n",
  571.                  GetCurrentThreadId(), reason));
  572.  
  573.     if (g_pShell->m_rgfActiveModes & DSM_ENHANCED_DIAGNOSTICS)
  574.     {
  575.         g_pShell->Write( L"Step complete:");
  576.         g_pShell->Write( StepTypeToString(reason) );
  577.         g_pShell->Write( L"\n" );
  578.     }
  579.  
  580.  
  581.     g_pShell->StepNotify(pThread, pStepper);
  582.  
  583.     pStepper->Release();
  584.  
  585.     // We only want to skip compiler stubs until we hit non-stub
  586.     // code
  587.     if (!g_pShell->m_needToSkipCompilerStubs ||
  588.         g_pShell->SkipCompilerStubs(pAppDomain, pThread))
  589.     {
  590.         g_pShell->m_needToSkipCompilerStubs = false;
  591.         
  592.         ICorDebugController *pController = GetControllerInterface(pAppDomain);
  593.         g_pShell->Stop(pController, pThread);
  594.         
  595.         if (pController != NULL)
  596.             pController->Release();
  597.     }
  598.     // else SkipCompilerStubs Continue()'d for us
  599.  
  600.     return S_OK;
  601. }
  602.  
  603. HRESULT DebuggerCallback::Break( ICorDebugAppDomain *pAppDomain,
  604.                ICorDebugThread *pThread)
  605. {
  606.     SPEW(fprintf(stderr, "[%d] DC::Break.\n", GetCurrentThreadId()));
  607.  
  608.     g_pShell->PrintThreadPrefix(pThread);
  609.     g_pShell->Write(L"user break\n");
  610.  
  611.     ICorDebugProcess *pProcess;
  612.     pAppDomain->GetProcess(&pProcess);
  613.  
  614.     g_pShell->Stop(pProcess, pThread);
  615.  
  616.     return S_OK;
  617. }
  618.  
  619. HRESULT DebuggerCallback::Exception( ICorDebugAppDomain *pAppDomain,
  620.                    ICorDebugThread *pThread,
  621.                    BOOL unhandled)
  622. {
  623.    ICorDebugController *pController = GetControllerInterface(pAppDomain);
  624.  
  625.     SPEW(fprintf(stderr, "[%d] DC::Exception.\n", GetCurrentThreadId()));
  626.  
  627.     if (!unhandled && g_pShell->m_catchException)
  628.     {
  629.         g_pShell->PrintThreadPrefix(pThread);
  630.         g_pShell->Write(L"Exception generated: ");
  631.  
  632.         ICorDebugValue *ex;
  633.         HRESULT hr = pThread->GetCurrentException(&ex);
  634.  
  635.         if (SUCCEEDED(hr))
  636.             g_pShell->PrintVariable(NULL, ex, 0, TRUE);
  637.         else
  638.         {
  639.             g_pShell->Write(L"Unexpected error occured: ");
  640.             g_pShell->ReportError(hr);
  641.         }
  642.  
  643.         g_pShell->Write(L"\n");
  644.  
  645.         g_pShell->Stop(pController, pThread);
  646.     }
  647.     else if (unhandled && g_pShell->m_catchUnhandled)
  648.     {
  649.         g_pShell->PrintThreadPrefix(pThread);
  650.         g_pShell->Write(L"Unhandled exception generated: ");
  651.  
  652.         ICorDebugValue *ex;
  653.         HRESULT hr = pThread->GetCurrentException(&ex);
  654.         if (SUCCEEDED(hr))
  655.             g_pShell->PrintVariable(NULL, ex, 0, TRUE);
  656.         else
  657.         {
  658.             g_pShell->Write(L"Unexpected error occured: ");
  659.             g_pShell->ReportError(hr);
  660.         }
  661.  
  662.         g_pShell->Write(L"\n");
  663.  
  664.         g_pShell->Stop(pController, pThread);
  665.     }
  666.     else
  667.         g_pShell->Continue(pController, pThread);
  668.  
  669.     if (pController != NULL)
  670.         pController->Release();
  671.  
  672.     return S_OK;
  673. }
  674.  
  675.  
  676. HRESULT DebuggerCallback::EvalComplete(ICorDebugAppDomain *pAppDomain,
  677.                                        ICorDebugThread *pThread,
  678.                                        ICorDebugEval *pEval)
  679. {
  680.     ICorDebugProcess *pProcess;
  681.     pAppDomain->GetProcess(&pProcess);
  682.  
  683.     g_pShell->PrintThreadPrefix(pThread);
  684.  
  685.     // Remember the most recently completed func eval for this thread.
  686.     DebuggerManagedThread *dmt = g_pShell->GetManagedDebuggerThread(pThread);
  687.     _ASSERTE(dmt != NULL);
  688.  
  689.     if (dmt->m_lastFuncEval)
  690.         RELEASE(dmt->m_lastFuncEval);
  691.  
  692.     dmt->m_lastFuncEval = pEval;
  693.  
  694.     // Print any current func eval result.
  695.     ICorDebugValue *pResult;
  696.     HRESULT hr = pEval->GetResult(&pResult);
  697.  
  698.     if (hr == S_OK)
  699.     {
  700.         g_pShell->Write(L"Function evaluation complete.\n");
  701.         g_pShell->PrintVariable(L"$result", pResult, 0, TRUE);
  702.     }
  703.     else if (hr == CORDBG_S_FUNC_EVAL_ABORTED)
  704.         g_pShell->Write(L"Function evaluation aborted.\n");
  705.     else if (hr == CORDBG_S_FUNC_EVAL_HAS_NO_RESULT)
  706.         g_pShell->Write(L"Function evaluation complete, no result.\n");
  707.     else
  708.         g_pShell->ReportError(hr);
  709.  
  710.     g_pShell->m_pCurrentEval = NULL;
  711.     
  712.     g_pShell->Stop(pProcess, pThread);
  713.  
  714.     return S_OK;
  715. }
  716.  
  717. HRESULT DebuggerCallback::EvalException(ICorDebugAppDomain *pAppDomain,
  718.                                         ICorDebugThread *pThread,
  719.                                         ICorDebugEval *pEval)
  720. {
  721.     ICorDebugProcess *pProcess;
  722.     pAppDomain->GetProcess(&pProcess);
  723.  
  724.     g_pShell->PrintThreadPrefix(pThread);
  725.     g_pShell->Write(L"Function evaluation completed with an exception.\n");
  726.  
  727.     // Remember the most recently completed func eval for this thread.
  728.     DebuggerManagedThread *dmt = g_pShell->GetManagedDebuggerThread(pThread);
  729.     _ASSERTE(dmt != NULL);
  730.  
  731.     if (dmt->m_lastFuncEval)
  732.         RELEASE(dmt->m_lastFuncEval);
  733.  
  734.     dmt->m_lastFuncEval = pEval;
  735.  
  736.     // Print any current func eval result.
  737.     ICorDebugValue *pResult;
  738.     HRESULT hr = pEval->GetResult(&pResult);
  739.  
  740.     if (hr == S_OK)
  741.         g_pShell->PrintVariable(L"$result", pResult, 0, TRUE);
  742.     
  743.     g_pShell->m_pCurrentEval = NULL;
  744.     
  745.     g_pShell->Stop(pProcess, pThread);
  746.  
  747.     return S_OK;
  748. }
  749.  
  750.  
  751. HRESULT DebuggerCallback::CreateThread( ICorDebugAppDomain *pAppDomain,
  752.                       ICorDebugThread *thread)
  753. {
  754.     SPEW(fprintf(stderr, "[%d] DC::CreateThread.\n", GetCurrentThreadId()));
  755.  
  756.     DWORD threadID;
  757.     HRESULT hr = thread->GetID(&threadID);
  758.     if (FAILED(hr))
  759.     {
  760.         g_pShell->Write(L"Unexpected error in CreateThread callback:");
  761.         g_pShell->ReportError(hr);
  762.         goto LExit;
  763.     }
  764.  
  765.     g_pShell->PrintThreadPrefix(thread, true);
  766.     g_pShell->Write(L"Thread created.\n");
  767.  
  768.     SPEW(fprintf(stderr, "[%d] DC::CT: Thread id is %d\n",
  769.                  GetCurrentThreadId(), threadID));
  770.  
  771.     hr = g_pShell->AddManagedThread( thread, threadID );
  772.     if (FAILED(hr))
  773.         goto LExit;
  774.  
  775.     SPEW(g_pShell->Write( L"interc? m_rgfActiveModes:0x%x\n",g_pShell->m_rgfActiveModes));
  776.     
  777.     if ((!g_pShell->m_gotFirstThread) ||
  778.                (g_pShell->m_catchThread))
  779.     {
  780.         // Try to skip compiler stubs. 
  781.         // SkipCompilerStubs returns TRUE if we're NOT in a stub
  782.         if (g_pShell->SkipCompilerStubs(pAppDomain, thread))
  783.         {
  784.             // If we don't need to skip a
  785.             // compiler stub on entry to the first thread, then we never
  786.             // will, so set the flag appropriately.
  787.             g_pShell->m_needToSkipCompilerStubs = false;
  788.             
  789.             // If we do skip the prolog, we're finished, so go
  790.             // to the clean-up code immediately
  791.             if (g_pShell->SkipProlog(pAppDomain, thread ) )
  792.                 goto LExit;
  793.  
  794.             ICorDebugController *pController = GetControllerInterface(pAppDomain);
  795.             g_pShell->Stop(pController, thread);
  796.  
  797.             if (pController != NULL)
  798.                 pController->Release();
  799.         }
  800.     }
  801.     else
  802.     {
  803.         ICorDebugController *controller = NULL;
  804.         controller = GetControllerInterface(pAppDomain);
  805.  
  806.         g_pShell->Continue(controller, thread);
  807.         
  808.         if (controller != NULL)
  809.             controller->Release();
  810.     }
  811.     
  812. LExit:
  813.     g_pShell->m_gotFirstThread = true;
  814.  
  815.     return hr;
  816. }
  817.  
  818.  
  819. HRESULT DebuggerCallback::ExitThread(ICorDebugAppDomain *pAppDomain,
  820.                                      ICorDebugThread *thread)
  821. {
  822.     SPEW(fprintf(stderr, "[%d] DC::ExitThread.\n", GetCurrentThreadId()));
  823.  
  824.     g_pShell->PrintThreadPrefix(thread, true);
  825.     g_pShell->Write(L"Thread exited.\n");
  826.  
  827.     ICorDebugController *pController = GetControllerInterface(pAppDomain);
  828.     g_pShell->Continue(pController, thread);
  829.  
  830.     if (pController != NULL)
  831.         pController->Release();
  832.  
  833.     SPEW(fprintf(stderr, "[%d] DC::ET: returning.\n", GetCurrentThreadId()));
  834.  
  835.     DWORD dwThreadId =0;
  836.     HRESULT hr = thread->GetID( &dwThreadId );
  837.     if (FAILED(hr) )
  838.         return hr;
  839.  
  840.     DebuggerManagedThread *dmt = g_pShell->GetManagedDebuggerThread(thread);
  841.     if (dmt != NULL)
  842.     {
  843.         g_pShell->RemoveManagedThread( dwThreadId );
  844.     }
  845.  
  846.     return S_OK;
  847. }
  848.  
  849. HRESULT DebuggerCallback::LoadModule( ICorDebugAppDomain *pAppDomain,
  850.                     ICorDebugModule *pModule)
  851. {
  852.     SPEW(fprintf(stderr, "[%d] DC::LoadModule.\n", GetCurrentThreadId()));
  853.  
  854.     HRESULT hr;
  855.  
  856.     DebuggerModule *m = new DebuggerModule(pModule);
  857.  
  858.     if (m == NULL)
  859.     {
  860.         g_pShell->ReportError(E_OUTOFMEMORY);
  861.         return (E_OUTOFMEMORY);
  862.     }
  863.  
  864.     hr = m->Init();
  865.  
  866.     if (FAILED(hr))
  867.     {
  868.         g_pShell->ReportError(hr);
  869.         return hr;
  870.     }
  871.  
  872.     hr = g_pShell->m_modules.AddBase(m);
  873.     _ASSERTE(SUCCEEDED(hr));
  874.  
  875.     WCHAR moduleName[256];
  876.     ULONG32 s;
  877.     
  878.     moduleName[0] = L'\0';
  879.     hr = pModule->GetName(256, &s, moduleName);
  880.     m->SetName (moduleName);
  881.  
  882.     DebuggerBreakpoint *bp = g_pShell->m_breakpoints;
  883.  
  884.     while (bp != NULL)
  885.     {
  886.         if (bp->Bind(m, NULL))
  887.             g_pShell->OnBindBreakpoint(bp, m);
  888.  
  889.         bp = bp->m_next;
  890.     }
  891.  
  892.     if ((g_pShell->m_rgfActiveModes & DSM_SHOW_MODULE_LOADS) ||
  893.         (g_pShell->m_catchModule))
  894.     {
  895.         _printModule(pModule, PT_CREATED);
  896.  
  897.         ICorDebugAssembly *pAssembly;
  898.         hr = pModule->GetAssembly(&pAssembly);
  899.         _ASSERTE(SUCCEEDED(hr));
  900.         
  901.         _printAssembly(pAssembly, PT_IN);
  902.         _printAppDomain(pAppDomain, PT_IN);
  903.     }
  904.  
  905.     hr = pModule->EnableClassLoadCallbacks(TRUE);
  906.  
  907.     if (FAILED(hr))
  908.         g_pShell->Write(L"Failed to enable class load callbacks for %s\n",
  909.                         moduleName);
  910.  
  911.     if (g_pShell->m_rgfActiveModes & DSM_ENABLE_JIT_OPTIMIZATIONS)
  912.     {
  913.         hr = pModule->EnableJITDebugging(TRUE, TRUE);
  914.  
  915.         if (FAILED(hr))
  916.             g_pShell->Write(L"Failed to enable JIT Optimizations for %s\n",
  917.                             moduleName);
  918.     }
  919.     
  920.     ICorDebugController *pController = GetControllerInterface(pAppDomain);
  921.     
  922.     if (g_pShell->m_catchModule)
  923.         g_pShell->Stop(pController, NULL);
  924.     else
  925.         g_pShell->Continue(pController, NULL);
  926.  
  927.     if (pController != NULL)
  928.         pController->Release();
  929.  
  930.     SPEW(fprintf(stderr, "[%d] DC::LM: continued.\n", GetCurrentThreadId()));
  931.  
  932.     return S_OK;
  933. }
  934.  
  935.  
  936. HRESULT DebuggerCallback::UnloadModule( ICorDebugAppDomain *pAppDomain,
  937.                       ICorDebugModule *pModule)
  938. {
  939.     SPEW(fprintf(stderr, "[%d] DC::UnloadModule.\n", GetCurrentThreadId()));
  940.  
  941.     DebuggerModule *m = DebuggerModule::FromCorDebug(pModule);
  942.     _ASSERTE(m != NULL);
  943.  
  944.     DebuggerBreakpoint *bp = g_pShell->m_breakpoints;
  945.     while (bp != NULL)
  946.     {
  947.         // Detatch the breakpoint, which means it is an active bp
  948.         // but doesn't have a NGWS object behind it.
  949.         if (bp->m_managed && bp->IsBoundToModule(m))
  950.             bp->Detach();
  951.  
  952.         bp = bp->m_next;
  953.     }
  954.  
  955.     g_pShell->m_modules.RemoveBase((ULONG)pModule);
  956.  
  957.     if ((g_pShell->m_rgfActiveModes & DSM_SHOW_MODULE_LOADS) || 
  958.         (g_pShell->m_catchModule))
  959.     {
  960.         _printModule(pModule, PT_EXITED);
  961.     }
  962.     
  963.     ICorDebugController *pController = GetControllerInterface(pAppDomain);
  964.     
  965.     if (g_pShell->m_catchModule)
  966.         g_pShell->Stop(pController, NULL);
  967.     else
  968.         g_pShell->Continue(pController, NULL);
  969.  
  970.     if (pController != NULL)
  971.         pController->Release();
  972.  
  973.     SPEW(fprintf(stderr, "[%d] DC::UM: continued.\n", GetCurrentThreadId()));
  974.  
  975.     return S_OK;
  976. }
  977.  
  978.  
  979. HRESULT DebuggerCallback::LoadClass( ICorDebugAppDomain *pAppDomain,
  980.                    ICorDebugClass *c)
  981. {
  982.     SPEW(fprintf(stderr, "[%d] DC::LoadClass.\n", GetCurrentThreadId()));
  983.  
  984.     DebuggerModule *dm = NULL;
  985.     DebuggerClass *cl = new DebuggerClass(c);
  986.  
  987.     if (cl == NULL)
  988.     {
  989.         g_pShell->ReportError(E_OUTOFMEMORY);
  990.         return (E_OUTOFMEMORY);
  991.     }
  992.  
  993.     HRESULT hr = S_OK;
  994.  
  995.     mdTypeDef td;
  996.     hr = c->GetToken(&td);
  997.  
  998.     if (SUCCEEDED(hr))
  999.     {
  1000.         ICorDebugModule *imodule;
  1001.         hr = c->GetModule(&imodule);
  1002.  
  1003.         if (SUCCEEDED(hr))
  1004.         {
  1005.             dm = DebuggerModule::FromCorDebug(imodule);
  1006.             _ASSERTE(dm != NULL);
  1007.  
  1008.             hr = dm->m_loadedClasses.AddBase(cl);
  1009.             _ASSERTE(SUCCEEDED(hr));
  1010.             
  1011.             WCHAR className[MAX_CLASS_NAME];
  1012.             ULONG classNameSize = 0;
  1013.  
  1014.             hr = dm->GetMetaData()->GetTypeDefProps(td,
  1015.                                                     className, MAX_CLASS_NAME,
  1016.                                                     &classNameSize,
  1017.                                                     NULL, NULL,
  1018.                                                     NULL);
  1019.  
  1020.             if (SUCCEEDED(hr))
  1021.             {
  1022.                 WCHAR *namespacename;
  1023.                 WCHAR *name;
  1024.  
  1025.                 namespacename = className;
  1026.                 name = wcsrchr(className, L'.');
  1027.                 if (name)
  1028.                     *name++ = 0;
  1029.                 else
  1030.                 {
  1031.                     namespacename = L"";
  1032.                     name = className;
  1033.                 }
  1034.  
  1035.                 cl->SetName (name, namespacename);
  1036.  
  1037.                 if ((g_pShell->m_rgfActiveModes & DSM_SHOW_CLASS_LOADS) ||
  1038.                     g_pShell->m_catchClass)
  1039.                 {
  1040.                     if (namespacename != NULL && *namespacename != NULL)
  1041.                         g_pShell->Write(L"Loaded class: %s.%s\n", namespacename, name);
  1042.                     else
  1043.                         g_pShell->Write(L"Loaded class: %s\n", name);        
  1044.                 }
  1045.             }
  1046.             else
  1047.                 g_pShell->ReportError(hr);
  1048.  
  1049.             RELEASE(imodule);
  1050.         }
  1051.         else
  1052.             g_pShell->ReportError(hr);
  1053.     }
  1054.     else
  1055.         g_pShell->ReportError(hr);
  1056.  
  1057.     // If this module is dynamic, then bind all breakpoints, as
  1058.     // they may have been bound to this class.
  1059.     ICorDebugModule *pMod = dm->GetICorDebugModule();
  1060.     _ASSERTE( pMod != NULL );
  1061.  
  1062.     BOOL fDynamic = false;
  1063.     hr = pMod->IsDynamic(&fDynamic);
  1064.     if (FAILED(hr))
  1065.     {
  1066.         g_pShell->Write( L"Unable to determine if loaded module is dynamic");
  1067.         g_pShell->Write( L"- not attempting\n to bind any breakpoints");
  1068.     }
  1069.     else
  1070.     {
  1071.         if (fDynamic)
  1072.         {
  1073.             DebuggerBreakpoint *bp = g_pShell->m_breakpoints;
  1074.  
  1075.             while (bp != NULL)
  1076.             {
  1077.                 if (bp->Bind(dm, NULL))
  1078.                     g_pShell->OnBindBreakpoint(bp, dm);
  1079.  
  1080.                 bp = bp->m_next;
  1081.             }
  1082.         }
  1083.     }
  1084.  
  1085.     ICorDebugController *pController = GetControllerInterface(pAppDomain);
  1086.     
  1087.     if (g_pShell->m_catchClass)
  1088.         g_pShell->Stop(pController, NULL);
  1089.     else
  1090.         g_pShell->Continue(pController, NULL);
  1091.  
  1092.     if (pController != NULL)
  1093.         pController->Release();
  1094.  
  1095.     SPEW(fprintf(stderr, "[%d] DC::LC: continued.\n", GetCurrentThreadId()));
  1096.  
  1097.     return S_OK;
  1098. }
  1099.  
  1100.  
  1101. HRESULT DebuggerCallback::UnloadClass( ICorDebugAppDomain *pAppDomain,
  1102.                      ICorDebugClass *c)
  1103. {
  1104.     SPEW(fprintf(stderr, "[%d] DC::UnloadClass.\n", GetCurrentThreadId()));
  1105.  
  1106.     HRESULT hr = S_OK;
  1107.     mdTypeDef td;
  1108.     hr = c->GetToken(&td);
  1109.  
  1110.     if (SUCCEEDED(hr))
  1111.     {
  1112.         ICorDebugModule *imodule;
  1113.         hr = c->GetModule(&imodule);
  1114.  
  1115.         if (SUCCEEDED(hr))
  1116.         {
  1117.             DebuggerModule *dm = DebuggerModule::FromCorDebug(imodule);
  1118.             _ASSERTE(dm != NULL);
  1119.  
  1120.             if ((g_pShell->m_rgfActiveModes & DSM_SHOW_CLASS_LOADS) ||
  1121.                 g_pShell->m_catchClass)
  1122.             {
  1123.  
  1124.  
  1125.                 WCHAR className[MAX_CLASS_NAME];
  1126.                 ULONG classNameSize = 0;
  1127.             
  1128.                 hr = dm->GetMetaData()->GetTypeDefProps(td,
  1129.                                                         className, MAX_CLASS_NAME,
  1130.                                                         &classNameSize,
  1131.                                                         NULL, NULL,
  1132.                                                         NULL);
  1133.  
  1134.                 if (SUCCEEDED(hr))
  1135.                     g_pShell->Write(L"Unloaded class: %s\n", className);
  1136.                 else
  1137.                     g_pShell->ReportError(hr);
  1138.             }
  1139.  
  1140.             hr = dm->m_loadedClasses.RemoveBase((ULONG)c);
  1141.             _ASSERTE(SUCCEEDED(hr));
  1142.  
  1143.             imodule->Release();
  1144.         }
  1145.         else
  1146.             g_pShell->ReportError(hr);
  1147.     }
  1148.     else
  1149.         g_pShell->ReportError(hr);
  1150.  
  1151.     ICorDebugController *pController = GetControllerInterface(pAppDomain);
  1152.     
  1153.     if (g_pShell->m_catchClass)
  1154.         g_pShell->Stop(pController, NULL);
  1155.     else
  1156.         g_pShell->Continue(pController, NULL);
  1157.  
  1158.     if (pController != NULL)
  1159.         pController->Release();
  1160.  
  1161.     SPEW(fprintf(stderr, "[%d] DC::LC: continued.\n", GetCurrentThreadId()));
  1162.  
  1163.     return S_OK;
  1164. }
  1165.  
  1166.  
  1167.  
  1168. HRESULT DebuggerCallback::DebuggerError(ICorDebugProcess *pProcess,
  1169.                                         HRESULT errorHR,
  1170.                                         DWORD errorCode)
  1171. {
  1172.     SPEW(fprintf(stderr, "[%d] DC::DebuggerError 0x%p (%d).\n",
  1173.                  GetCurrentThreadId(), errorHR, errorCode));
  1174.  
  1175.     return (S_OK);
  1176. }
  1177.  
  1178.  
  1179. HRESULT DebuggerCallback::LogMessage(ICorDebugAppDomain *pAppDomain,
  1180.                   ICorDebugThread *pThread,
  1181.                   LONG lLevel,
  1182.                   WCHAR *pLogSwitchName,
  1183.                   WCHAR *pMessage)
  1184. {
  1185.     DWORD dwThreadId = 0;
  1186.  
  1187.     pThread->GetID(&dwThreadId);
  1188.  
  1189.     if(g_pShell->m_rgfActiveModes & DSM_LOGGING_MESSAGES)
  1190.     {
  1191.         g_pShell->Write (L"LOG_MESSAGE: TID=0x%x Category:Severity=%s:%d Message=\n%s\n",
  1192.             dwThreadId, pLogSwitchName, lLevel, pMessage);
  1193.     }
  1194.     else
  1195.     {
  1196.         // If we don't want to get messages, then tell the other side to stop
  1197.         // sending them....
  1198.         ICorDebugProcess *process = NULL;
  1199.         HRESULT hr = S_OK;
  1200.         hr = pAppDomain->GetProcess(&process);
  1201.         if (!FAILED(hr))
  1202.         {
  1203.             process->EnableLogMessages(FALSE);
  1204.             process->Release();
  1205.         }
  1206.     }
  1207.     ICorDebugController *pController = GetControllerInterface(pAppDomain);
  1208.     g_pShell->Continue(pController, NULL);
  1209.  
  1210.     if (pController != NULL)
  1211.         pController->Release();
  1212.  
  1213.     return S_OK;
  1214. }
  1215.  
  1216.  
  1217. HRESULT DebuggerCallback::LogSwitch(ICorDebugAppDomain *pAppDomain,
  1218.                   ICorDebugThread *pThread,
  1219.                   LONG lLevel,
  1220.                   ULONG ulReason,
  1221.                   WCHAR *pLogSwitchName,
  1222.                   WCHAR *pParentName)
  1223. {
  1224.     ICorDebugController *pController = GetControllerInterface(pAppDomain);
  1225.     g_pShell->Continue(pController, NULL);
  1226.  
  1227.     if (pController != NULL)
  1228.         pController->Release();
  1229.  
  1230.     return S_OK;
  1231. }
  1232.  
  1233. HRESULT DebuggerCallback::ControlCTrap(ICorDebugProcess *pProcess)
  1234. {
  1235.     SPEW(fprintf(stderr, "[%d] DC::ControlC.\n", GetCurrentThreadId()));
  1236.  
  1237.     g_pShell->Write(L"ControlC Trap\n");
  1238.  
  1239.     g_pShell->Stop(pProcess, NULL);
  1240.  
  1241.     return S_OK;
  1242. }
  1243.  
  1244. HRESULT DebuggerCallback::NameChange(ICorDebugAppDomain *pAppDomain, 
  1245.                                      ICorDebugThread *pThread)
  1246. {
  1247.     ICorDebugProcess *pProcess = NULL;
  1248.     if (pAppDomain)
  1249.         pAppDomain->GetProcess(&pProcess);
  1250.     else
  1251.     {
  1252.         _ASSERTE (pThread != NULL);
  1253.         pThread->GetProcess(&pProcess);
  1254.     }
  1255.  
  1256.     g_pShell->Continue(pProcess, NULL);
  1257.  
  1258.     return S_OK;
  1259. }
  1260.  
  1261.  
  1262. HRESULT DebuggerCallback::UpdateModuleSymbols(ICorDebugAppDomain *pAppDomain,
  1263.                                               ICorDebugModule *pModule,
  1264.                                               IStream *pSymbolStream)
  1265. {
  1266.     ICorDebugProcess *pProcess;
  1267.     pAppDomain->GetProcess(&pProcess);
  1268.  
  1269.     HRESULT hr;
  1270.  
  1271.     DebuggerModule *m = DebuggerModule::FromCorDebug(pModule);
  1272.     _ASSERTE(m != NULL);
  1273.  
  1274.     WCHAR moduleName[256];
  1275.     ULONG32 s;
  1276.     
  1277.     moduleName[0] = L'\0';
  1278.     hr = pModule->GetName(256, &s, moduleName);
  1279.  
  1280.     hr = m->UpdateSymbols(pSymbolStream);
  1281.  
  1282.     if (SUCCEEDED(hr))
  1283.         g_pShell->Write(L"Updated symbols for module %s\n", moduleName);
  1284.     else
  1285.         g_pShell->Write(L"Update of symbols for module %s failed with "
  1286.                         L"0x%08x\n", moduleName, hr);
  1287.     
  1288.     g_pShell->Continue(pProcess, NULL);
  1289.  
  1290.     return S_OK;
  1291. }
  1292.  
  1293.  
  1294. HRESULT DebuggerUnmanagedCallback::DebugEvent(LPDEBUG_EVENT event,
  1295.                                                BOOL fIsOutOfBand)
  1296. {
  1297.     SPEW(fprintf(stderr, "[%d] DUC::DebugEvent.\n", GetCurrentThreadId()));
  1298.  
  1299.     // Find the process this event is for.
  1300.     ICorDebugProcess *pProcess;
  1301.     HRESULT hr = g_pShell->m_cor->GetProcess(event->dwProcessId, &pProcess);
  1302.  
  1303.     if (FAILED(hr) || pProcess == NULL)
  1304.     {
  1305.         g_pShell->ReportError(hr);
  1306.         return hr;
  1307.     }
  1308.  
  1309.     // Snagg the handle for this process.
  1310.     HPROCESS hProcess;
  1311.     hr = pProcess->GetHandle(&hProcess);
  1312.  
  1313.     if (FAILED(hr))
  1314.     {
  1315.         g_pShell->ReportError(hr);
  1316.         RELEASE(pProcess);
  1317.         return hr;
  1318.     }
  1319.  
  1320.     // Find the thread this event is for.
  1321.     ICorDebugThread *pThread;
  1322.     hr = pProcess->GetThread(event->dwThreadId, &pThread);
  1323.  
  1324.     if (FAILED(hr))
  1325.         pThread = NULL;
  1326.  
  1327.     //
  1328.     // Find the unmanaged thread this event is for.
  1329.     //
  1330.  
  1331.     DebuggerUnmanagedThread *ut = (DebuggerUnmanagedThread*) 
  1332.       g_pShell->m_unmanagedThreads.GetBase(event->dwThreadId);
  1333.             
  1334.     // We need to skip the first exception we get and simply clear it
  1335.     // since its the entrypoint excetpion.
  1336.  
  1337.     bool stopNow = false;
  1338.  
  1339.     switch (event->dwDebugEventCode)
  1340.     {
  1341.     case CREATE_PROCESS_DEBUG_EVENT:
  1342.         {
  1343.             g_pShell->m_unmanagedDebuggingEnabled = true;
  1344.             
  1345.             if (g_pShell->m_rgfActiveModes & DSM_SHOW_UNMANAGED_TRACE)
  1346.                 g_pShell->Write(L"Create Process, Thread=0x%x\n",
  1347.                                 event->dwThreadId);
  1348.  
  1349.             g_pShell->HandleUnmanagedThreadCreate(
  1350.                                        event->dwThreadId,
  1351.                                        event->u.CreateProcessInfo.hThread);
  1352.             
  1353.             BOOL succ = SymInitialize(hProcess, NULL, FALSE);
  1354.  
  1355.             if (succ)
  1356.             {
  1357.                 g_pShell->LoadUnmanagedSymbols(
  1358.                                      hProcess,
  1359.                                      event->u.CreateProcessInfo.hFile,
  1360.                               (DWORD)event->u.CreateProcessInfo.lpBaseOfImage);
  1361.             }
  1362.             else
  1363.                 g_pShell->Write(L"Error initializing symbol loader.\n");
  1364.         }
  1365.  
  1366.         break;
  1367.  
  1368.     case EXIT_PROCESS_DEBUG_EVENT:
  1369.         {
  1370.             if (g_pShell->m_rgfActiveModes & DSM_SHOW_UNMANAGED_TRACE)
  1371.                 g_pShell->Write(L"Exit Process, Thread=0x%x\n",
  1372.                                 event->dwThreadId);
  1373.  
  1374.             DebuggerBreakpoint *bp = g_pShell->m_breakpoints;
  1375.  
  1376.             while (bp != NULL)
  1377.             {
  1378.                 if (!bp->m_managed && bp->m_process == pProcess)
  1379.                 {
  1380.                     // Set the process to 0 to prevent the call to
  1381.                     // UnapplyUnmanagedPatch, which will fail because
  1382.                     // most of the process memory is unmapped now.
  1383.                     bp->m_process = 0;
  1384.                     
  1385.                     bp->Detach();
  1386.                 }
  1387.  
  1388.                 bp = bp->m_next;
  1389.             }
  1390.  
  1391.             g_pShell->m_unmanagedThreads.RemoveBase(event->dwThreadId);
  1392.             SymCleanup(hProcess);
  1393.  
  1394.             g_pShell->m_unmanagedDebuggingEnabled = false;
  1395.         }
  1396.     
  1397.         break;
  1398.  
  1399.     case CREATE_THREAD_DEBUG_EVENT:
  1400.         if (g_pShell->m_rgfActiveModes & DSM_SHOW_UNMANAGED_TRACE)
  1401.             g_pShell->Write(L"Create Thread, Id=0x%x\n", event->dwThreadId);
  1402.  
  1403.         g_pShell->HandleUnmanagedThreadCreate(event->dwThreadId,
  1404.                                               event->u.CreateThread.hThread);
  1405.         break;
  1406.  
  1407.     case EXIT_THREAD_DEBUG_EVENT:
  1408.         if (g_pShell->m_rgfActiveModes & DSM_SHOW_UNMANAGED_TRACE)
  1409.             g_pShell->Write(L"Exit Thread, Id=0x%x\n", event->dwThreadId);
  1410.  
  1411.         g_pShell->m_unmanagedThreads.RemoveBase(event->dwThreadId);
  1412.         break;
  1413.  
  1414.     case EXCEPTION_DEBUG_EVENT:
  1415.         if (g_pShell->m_rgfActiveModes & DSM_SHOW_UNMANAGED_TRACE)
  1416.             g_pShell->Write(L"Exception, Thread=0x%x, Code=0x%08x, "
  1417.                             L"Addr=0x%08x, Chance=%d\n",
  1418.                             event->dwThreadId,
  1419.                             event->u.Exception.ExceptionRecord.ExceptionCode,
  1420.                             event->u.Exception.ExceptionRecord.ExceptionAddress,
  1421.                             event->u.Exception.dwFirstChance);
  1422.  
  1423.         if (g_pShell->m_targetProcessHandledFirstException == false)
  1424.         {
  1425.             if (g_pShell->m_rgfActiveModes & DSM_SHOW_UNMANAGED_TRACE)
  1426.                 g_pShell->Write(L"Skipping first exception event.\n");
  1427.                 
  1428.             g_pShell->m_targetProcessHandledFirstException = true;
  1429.             hr = pProcess->ClearCurrentException(event->dwThreadId);
  1430.             _ASSERTE(SUCCEEDED(hr));
  1431.             break;
  1432.         }
  1433.  
  1434.         if (event->u.Exception.ExceptionRecord.ExceptionCode == STATUS_SINGLE_STEP)
  1435.         {
  1436.             bool clear = false;
  1437.             
  1438.             // Reenable any breakpoints we were skipping over in this
  1439.             // thread. (We turn on tracing to get over unmanaged
  1440.             // breakpoints, so this might be the only reason we were
  1441.             // stepping.)
  1442.             DebuggerBreakpoint *bp = g_pShell->m_breakpoints;
  1443.  
  1444.             while (bp != NULL)
  1445.             {
  1446.                 if (!bp->m_managed 
  1447.                     && bp->m_process == pProcess
  1448.                     && bp->m_skipThread == event->dwThreadId)
  1449.                 {
  1450.                     clear = true;
  1451.                     bp->Attach();
  1452.                 }
  1453.  
  1454.                 bp = bp->m_next;
  1455.             }
  1456.             
  1457.             // Handle any unmanaged single stepping that we were doing
  1458.             if (ut != NULL && ut->m_stepping)
  1459.             {
  1460.                 clear = true;
  1461.                 
  1462.                 // In order to properly handle a single step, we need
  1463.                 // to see if we're on a transition stub now. To do
  1464.                 // that, we have to communicate with the inprocess
  1465.                 // portion of the debugging services, and we can't do
  1466.                 // that from inside of the unmanaged callback. So we
  1467.                 // copy the event to the DebuggerShell and go ahead
  1468.                 // and tell the shell to stop. The shell will pickup
  1469.                 // the event and finish processing it.
  1470.  
  1471.                 // Copy the whole event...
  1472.                 g_pShell->m_lastUnmanagedEvent = *event;
  1473.                 g_pShell->m_handleUnmanagedEvent = true;
  1474.                 stopNow = true;
  1475.             }
  1476.  
  1477.             // Clear single step exceptions if we're the reason we
  1478.             // were stepping the thread.
  1479.             if (clear)
  1480.             {
  1481.                 hr = pProcess->ClearCurrentException(event->dwThreadId);
  1482.                 if (FAILED(hr))
  1483.                     g_pShell->ReportError(hr);
  1484.             }
  1485.         }
  1486.         else if (event->u.Exception.ExceptionRecord.ExceptionCode == STATUS_BREAKPOINT)
  1487.         {
  1488.             bool clear = false;
  1489.             
  1490.             DebuggerBreakpoint *bp = g_pShell->m_breakpoints;
  1491.  
  1492.             while (bp != NULL)
  1493.             {
  1494.                 if (!bp->m_managed 
  1495.                     && bp->MatchUnmanaged((CORDB_ADDRESS)
  1496.                                       event->u.Exception.ExceptionRecord.ExceptionAddress))
  1497.                 {
  1498.                     g_pShell->PrintThreadPrefix(pThread);
  1499.                     g_pShell->Write(L"break at ");
  1500.                     g_pShell->PrintBreakpoint(bp);
  1501.  
  1502.                     clear = true;
  1503.  
  1504.                     bp->Detach();
  1505.                     bp->m_skipThread = event->dwThreadId;
  1506.                 }
  1507.  
  1508.                 bp = bp->m_next;
  1509.             }
  1510.  
  1511.             if (clear)
  1512.             {
  1513.                 //
  1514.                 // Stop here
  1515.                 //
  1516.  
  1517.                 stopNow = true;
  1518.  
  1519.                 //
  1520.                 // Enable single stepping on this thread so 
  1521.                 // we can restore the breakpoint later
  1522.                 //
  1523.  
  1524.                 CONTEXT context;
  1525.                 context.ContextFlags = CONTEXT_FULL;
  1526.                 hr = pProcess->GetThreadContext(event->dwThreadId,
  1527.                                                 sizeof(context), (BYTE*)&context);
  1528.                 if (FAILED(hr))
  1529.                     g_pShell->ReportError(hr);
  1530.  
  1531. #ifdef _X86_
  1532.                 context.EFlags |= 0x100;
  1533. #else // !_X86_
  1534.                 _ASSERTE(!"@TODO Alpha - DebugEvent (dShell.cpp)");
  1535. #endif // _X86_
  1536.  
  1537.                 hr = pProcess->SetThreadContext(event->dwThreadId,
  1538.                                                 sizeof(context), (BYTE*)&context);
  1539.                 if (FAILED(hr))
  1540.                     g_pShell->ReportError(hr);
  1541.  
  1542.                 //
  1543.                 // Clear the exception
  1544.                 //
  1545.  
  1546.                 hr = pProcess->ClearCurrentException(event->dwThreadId);
  1547.                 if (FAILED(hr))
  1548.                     g_pShell->ReportError(hr);
  1549.  
  1550.             }
  1551.             else
  1552.             {
  1553.                 // User breakpoint in unmanaged code...
  1554.                 stopNow = true;
  1555.                 
  1556.                 if (pThread)
  1557.                 {
  1558.                     g_pShell->PrintThreadPrefix(pThread);
  1559.                     g_pShell->Write(L"User breakpoint reached.\n");
  1560.                 }
  1561.                 else
  1562.                     g_pShell->Write(L"User breakpoint reached on "
  1563.                                     L"unmanaged thread id 0x%x (%d)\n",
  1564.                                     event->dwThreadId,
  1565.                                     event->dwThreadId);
  1566.  
  1567.                 hr = pProcess->ClearCurrentException(event->dwThreadId);
  1568.                 if (FAILED(hr))
  1569.                     g_pShell->ReportError(hr);
  1570.             }
  1571.         }
  1572.         else
  1573.             stopNow = true;
  1574.  
  1575.         break;
  1576.  
  1577.     case LOAD_DLL_DEBUG_EVENT:
  1578.         g_pShell->LoadUnmanagedSymbols(hProcess,
  1579.                                        event->u.LoadDll.hFile,
  1580.                                        (DWORD)event->u.LoadDll.lpBaseOfDll);
  1581.  
  1582.         {
  1583.             DebuggerBreakpoint *bp = g_pShell->m_breakpoints;
  1584.  
  1585.             while (bp != NULL)
  1586.             {
  1587.                 bp->BindUnmanaged(pProcess,
  1588.                                   (DWORD)event->u.LoadDll.lpBaseOfDll);
  1589.                 bp = bp->m_next;
  1590.             }
  1591.         }
  1592.  
  1593.         break;
  1594.  
  1595.     case UNLOAD_DLL_DEBUG_EVENT:
  1596.         {
  1597.             if (g_pShell->m_rgfActiveModes & DSM_SHOW_UNMANAGED_TRACE)
  1598.                 g_pShell->Write(L"Unload DLL, base=0x%08x\n",
  1599.                                 event->u.UnloadDll.lpBaseOfDll);
  1600.  
  1601.             DebuggerBreakpoint *bp = g_pShell->m_breakpoints;
  1602.             while (bp != NULL)
  1603.             {
  1604.                 // Detatch the breakpoint, which means it is an active bp
  1605.                 // but doesn't have a NGWS object behind it.
  1606.                 if (!bp->m_managed &&
  1607.                     (bp->m_unmanagedModuleBase ==
  1608.                      (CORDB_ADDRESS)event->u.UnloadDll.lpBaseOfDll))
  1609.                     bp->Detach();
  1610.  
  1611.                 bp = bp->m_next;
  1612.             }
  1613.  
  1614.             SymUnloadModule(hProcess, (DWORD)event->u.UnloadDll.lpBaseOfDll);
  1615.         }
  1616.         break;
  1617.  
  1618.     case OUTPUT_DEBUG_STRING_EVENT:
  1619.         if (g_pShell->m_rgfActiveModes & DSM_SHOW_UNMANAGED_TRACE)
  1620.             g_pShell->Write(L"Output Debug String, Thread=0x%x\n",
  1621.                             event->dwThreadId);
  1622.  
  1623.         // Read the string.
  1624.         if (event->u.DebugString.nDebugStringLength > 0)
  1625.         {
  1626.             BYTE *stringBuf =
  1627.                 new BYTE[event->u.DebugString.nDebugStringLength];
  1628.  
  1629.             if (stringBuf)
  1630.             {
  1631.                 SIZE_T read = 0;
  1632.                 hr = pProcess->ReadMemory(
  1633.                       (CORDB_ADDRESS) event->u.DebugString.lpDebugStringData,
  1634.                                       event->u.DebugString.nDebugStringLength,
  1635.                                       stringBuf, &read );
  1636.  
  1637.                 if (SUCCEEDED(hr) && event->u.DebugString.nDebugStringLength ==
  1638.                     read)
  1639.                 {
  1640.                     if (event->u.DebugString.fUnicode)
  1641.                         g_pShell->Write(L"Thread 0x%x: %s",
  1642.                                         event->dwThreadId, stringBuf);
  1643.                     else
  1644.                         g_pShell->Write(L"Thread 0x%x: %S",
  1645.                                         event->dwThreadId, stringBuf);
  1646.                 }
  1647.             
  1648.                 delete [] stringBuf;
  1649.             }
  1650.         }
  1651.         
  1652.         // Must clear output debug strings for some reason.
  1653.         hr = pProcess->ClearCurrentException(event->dwThreadId);
  1654.         _ASSERTE(SUCCEEDED(hr));
  1655.         break;
  1656.  
  1657.     case RIP_EVENT:
  1658.         if (g_pShell->m_rgfActiveModes & DSM_SHOW_UNMANAGED_TRACE)
  1659.             g_pShell->Write(L"RIP, Thread=0x%x\n", event->dwThreadId);
  1660.         break;
  1661.  
  1662.     default:
  1663.         if (g_pShell->m_rgfActiveModes & DSM_SHOW_UNMANAGED_TRACE)
  1664.             g_pShell->Write(L"Unknown event %d, Thread=0x%x\n",
  1665.                             event->dwDebugEventCode,
  1666.                             event->dwThreadId);
  1667.         break;
  1668.     }
  1669.  
  1670.     ICorDebugController *pController = NULL;
  1671.     
  1672.     hr = pProcess->QueryInterface(IID_ICorDebugController,
  1673.                                   (void**)&pController);
  1674.     if (FAILED(hr))
  1675.         goto LError;
  1676.     
  1677.     if (stopNow)
  1678.     {
  1679.         _ASSERTE(fIsOutOfBand == FALSE);
  1680.         g_pShell->Stop(pController, pThread, ut);
  1681.     }
  1682.     else
  1683.         g_pShell->Continue(pController, pThread, ut, fIsOutOfBand);
  1684.  
  1685. LError:
  1686.     pProcess->Release();
  1687.     
  1688.     if (pController != NULL)
  1689.         pController->Release();
  1690.  
  1691.     if (pThread != NULL)
  1692.         pThread->Release();
  1693.     
  1694.     return (S_OK);
  1695. }
  1696.  
  1697. bool DebuggerShell::HandleUnmanagedEvent(void)
  1698. {
  1699.     // Mark that we've handled the unmanaged event.
  1700.     g_pShell->m_handleUnmanagedEvent = false;
  1701.     
  1702.     DEBUG_EVENT *event = &m_lastUnmanagedEvent;
  1703.     
  1704.     // Find the process this event is for.
  1705.     ICorDebugProcess *pProcess;
  1706.     HRESULT hr = m_cor->GetProcess(event->dwProcessId, &pProcess);
  1707.  
  1708.     if (FAILED(hr))
  1709.     {
  1710.         ReportError(hr);
  1711.         return false;
  1712.     }
  1713.  
  1714.     // Find the thread this event is for, if any.
  1715.     ICorDebugThread *pThread;
  1716.     hr = pProcess->GetThread(event->dwThreadId, &pThread);
  1717.  
  1718.     if (FAILED(hr))
  1719.         pThread = NULL;
  1720.  
  1721.     // Find the unmanaged thread this event is for.
  1722.     DebuggerUnmanagedThread *ut = (DebuggerUnmanagedThread*) 
  1723.         m_unmanagedThreads.GetBase(event->dwThreadId);
  1724.  
  1725.     // Finish up stepping work...
  1726.     if (event->dwDebugEventCode == EXCEPTION_DEBUG_EVENT)
  1727.     {
  1728.         if (event->u.Exception.ExceptionRecord.ExceptionCode ==
  1729.             STATUS_SINGLE_STEP)
  1730.         {
  1731.             _ASSERTE(ut != NULL);
  1732.             _ASSERTE(ut->m_stepping);
  1733.             
  1734.             ut->m_stepping = FALSE;
  1735.  
  1736.             // See if we're still in unmanaged code.
  1737.             BOOL managed = FALSE;
  1738.  
  1739.             CONTEXT context;
  1740.             context.ContextFlags = CONTEXT_FULL;
  1741.             hr = pProcess->GetThreadContext(ut->GetId(), 
  1742.                                             sizeof(context), (BYTE*)&context);
  1743.             if (FAILED(hr))
  1744.             {
  1745.                 Write(L"Cannot get thread context.\n");
  1746.                 ReportError(hr);
  1747.                 return false;
  1748.             }
  1749.  
  1750. #ifdef _X86_
  1751.             if (ut->m_unmanagedStackEnd != NULL
  1752.                 && context.Esp > ut->m_unmanagedStackEnd)
  1753.             {
  1754.                 // If we've stepped out of the unmanaged stack range,
  1755.                 // we're returning to managed code.
  1756.                 managed = TRUE;
  1757.             }
  1758.             else
  1759.             {
  1760.                 // If this is a managed stub, we're calling managed
  1761.                 // code.
  1762.                 BOOL stub;
  1763.                 hr = pProcess->IsTransitionStub(context.Eip, &stub);
  1764.  
  1765.                 if (FAILED(hr))
  1766.                 {
  1767.                     Write(L"Cannot tell if it's a stub\n");
  1768.                     ReportError(hr);
  1769.                     return false;
  1770.                 }
  1771.                 else if (stub)
  1772.                 {
  1773.                     managed = TRUE;
  1774.                 }
  1775.             }
  1776. #else // !_X86_
  1777.             _ASSERTE(!"@TODO Alpha - HandleUnmanagedEvent (dShell.cpp)");
  1778. #endif // _X86_
  1779.                 
  1780.             if (managed)
  1781.             {
  1782.                 // Create a managed stepper & let it go.
  1783.                 ICorDebugStepper *pStepper;
  1784.  
  1785.                 _ASSERTE(pThread != NULL);
  1786.                 hr = pThread->CreateStepper(&pStepper);
  1787.                 if (FAILED(hr))
  1788.                 {
  1789.                     ReportError(hr);
  1790.                     return false;
  1791.                 }
  1792.  
  1793.                 hr = pStepper->Step(TRUE);
  1794.                 if (FAILED(hr))
  1795.                 {
  1796.                     RELEASE(pStepper);
  1797.                     ReportError(hr);
  1798.                     return false;
  1799.                 }
  1800.  
  1801.                 StepStart(pThread, pStepper);
  1802.                 m_showSource = true;
  1803.  
  1804.                 // Return that we should continue the process without
  1805.                 // notifying the user.
  1806.                 return true;
  1807.             }
  1808.             else
  1809.             {
  1810.                 // Stop here.
  1811.                 StepNotify(pThread, NULL);
  1812.                 return false;
  1813.             }
  1814.         }
  1815.     }
  1816.     
  1817.     return false;
  1818. }
  1819.  
  1820. /* ------------------------------------------------------------------------- *
  1821.  * DebuggerShell methods
  1822.  * ------------------------------------------------------------------------- */
  1823.  
  1824. DebuggerShell::DebuggerShell(FILE *i, FILE *o) : 
  1825.     m_in(i),
  1826.     m_out(o),
  1827.     m_cor(NULL),
  1828.     m_modules(11), 
  1829.     m_unmanagedThreads(11),
  1830.     m_managedThreads(17),
  1831.     m_lastStepper(NULL),
  1832.     m_targetProcess(NULL),
  1833.     m_targetProcessHandledFirstException(false),
  1834.     m_currentProcess(NULL),
  1835.     m_currentThread(NULL),
  1836.     m_currentChain(NULL),
  1837.     m_rawCurrentFrame(NULL),
  1838.     m_currentFrame(NULL),
  1839.     m_showSource(true),
  1840.     m_silentTracing(false),
  1841.     m_quit(false),
  1842.     m_breakpoints(NULL),
  1843.     m_lastBreakpointID(0),
  1844. #ifdef _INTERNAL_DEBUG_SUPPORT_
  1845.     m_pDIS(NULL),
  1846. #endif
  1847.     m_currentSourcesPath(NULL),
  1848.     m_stopEvent(NULL),
  1849.     m_hProcessCreated(NULL),
  1850.     m_stop(false),
  1851.     m_lastRunArgs(NULL),
  1852.     m_catchException(false),
  1853.     m_catchUnhandled(true),
  1854.     m_catchClass(false),
  1855.     m_catchModule(false),
  1856.     m_catchThread(false),
  1857.     m_needToSkipCompilerStubs(true),
  1858.     m_invalidCache(false),
  1859.     m_rgfActiveModes(DSM_DEFAULT_MODES),
  1860.     m_handleUnmanagedEvent(false),
  1861.     m_unmanagedDebuggingEnabled(false),
  1862.     m_cEditAndContinues(0),
  1863.     m_pCurrentEval(NULL)
  1864. {
  1865.     
  1866. }
  1867.  
  1868. CorDebugUnmappedStop DebuggerShell::ComputeStopMask(void )
  1869. {
  1870.     unsigned int us = (unsigned int)STOP_NONE;
  1871.  
  1872.     if (m_rgfActiveModes & DSM_UNMAPPED_STOP_PROLOG )
  1873.         us |= (unsigned int)STOP_PROLOG;
  1874.  
  1875.     if (m_rgfActiveModes & DSM_UNMAPPED_STOP_EPILOG )
  1876.         us |= (unsigned int)STOP_EPILOG;
  1877.  
  1878.     if (m_rgfActiveModes & DSM_UNMAPPED_STOP_UNMANAGED )
  1879.         us |= (unsigned int)STOP_UNMANAGED;
  1880.     
  1881.     if (m_rgfActiveModes & DSM_UNMAPPED_STOP_ALL )   
  1882.         us |= (unsigned int)STOP_ALL;
  1883.  
  1884.     return (CorDebugUnmappedStop)us;
  1885. }
  1886.  
  1887. CorDebugIntercept DebuggerShell::ComputeInterceptMask( void )
  1888. {
  1889.     unsigned int is = (unsigned int)INTERCEPT_NONE;
  1890.  
  1891.     if (m_rgfActiveModes & DSM_INTERCEPT_STOP_CLASS_INIT )
  1892.         is |= (unsigned int)INTERCEPT_CLASS_INIT;
  1893.  
  1894.     if (m_rgfActiveModes & DSM_INTERCEPT_STOP_EXCEPTION_FILTER )         
  1895.         is |= (unsigned int)INTERCEPT_EXCEPTION_FILTER;
  1896.     
  1897.     if (m_rgfActiveModes & DSM_INTERCEPT_STOP_SECURITY)
  1898.         is |= (unsigned int)INTERCEPT_SECURITY;
  1899.             
  1900.     if (m_rgfActiveModes & DSM_INTERCEPT_STOP_CONTEXT_POLICY)
  1901.         is |= (unsigned int)INTERCEPT_CONTEXT_POLICY;
  1902.             
  1903.     if (m_rgfActiveModes & DSM_INTERCEPT_STOP_INTERCEPTION )
  1904.         is |= (unsigned int)INTERCEPT_INTERCEPTION;
  1905.             
  1906.     if (m_rgfActiveModes & DSM_INTERCEPT_STOP_ALL)
  1907.         is |= (unsigned int)INTERCEPT_ALL;
  1908.  
  1909.     return (CorDebugIntercept)is;
  1910. }
  1911.  
  1912.  
  1913.  
  1914. //
  1915. // InvokeDebuggerOnBreak is a console control handler which 
  1916. // breaks into the debugger when a break signal is received.
  1917. //
  1918.  
  1919. static BOOL WINAPI InvokeDebuggerOnBreak(DWORD dwCtrlType)
  1920. {
  1921.     if (dwCtrlType == CTRL_BREAK_EVENT)
  1922.     {
  1923.         if (g_pShell->m_pCurrentEval == NULL)
  1924.         {
  1925.             g_pShell->Write(L"\n\nBreaking current process.\n");
  1926.             g_pShell->Interrupt();
  1927.         }
  1928.         else
  1929.         {
  1930.             g_pShell->Write(L"\n\nAborting func eval...\n");
  1931.             HRESULT hr = g_pShell->m_pCurrentEval->Abort();
  1932.  
  1933.             if (FAILED(hr))
  1934.             {
  1935.                 g_pShell->Write(L"Abort failed\n");
  1936.                 g_pShell->ReportError(hr);
  1937.             }
  1938.         }
  1939.         
  1940.         return (TRUE);
  1941.     }
  1942.     else if ((dwCtrlType == CTRL_C_EVENT) &&
  1943.              (g_pShell->m_rgfActiveModes & DSM_WIN32_DEBUGGER))
  1944.     {
  1945.         g_pShell->Write(L"\n\nTracing all unmanaged stacks.\n");
  1946.         g_pShell->TraceAllUnmanagedThreadStacks();
  1947.  
  1948.         return (TRUE);
  1949.     }
  1950.     
  1951.     return (FALSE);
  1952. }
  1953.  
  1954.  
  1955. DebuggerShell::~DebuggerShell()
  1956. {
  1957.     SetTargetProcess(NULL);
  1958.     SetCurrentThread(NULL, NULL);
  1959.     SetCurrentChain( NULL );
  1960.  
  1961.     SetConsoleCtrlHandler(InvokeDebuggerOnBreak, FALSE);
  1962.  
  1963.     if (m_cor)
  1964.     {
  1965.         m_cor->Terminate();
  1966.         m_cor->Release();
  1967.     }
  1968.  
  1969.     if (m_currentSourcesPath)
  1970.         delete [] m_currentSourcesPath;
  1971.  
  1972.     if (m_stopEvent)
  1973.         CloseHandle(m_stopEvent);
  1974.  
  1975.     if (m_hProcessCreated)
  1976.         CloseHandle(m_hProcessCreated);
  1977.  
  1978. #ifdef _INTERNAL_DEBUG_SUPPORT_
  1979.     if (m_pDIS != NULL)
  1980.         delete m_pDIS;
  1981. #endif
  1982.  
  1983.     while (m_breakpoints)
  1984.         delete m_breakpoints;
  1985.  
  1986.     if (g_pShell == this)
  1987.         g_pShell = NULL;
  1988.  
  1989.     delete [] m_lastRunArgs;
  1990.  
  1991.     //clear out any managed threads that were left lieing around
  1992.     HASHFIND find;
  1993.     DebuggerManagedThread *dmt =NULL;
  1994.     for (dmt = (DebuggerManagedThread*)m_managedThreads.FindFirst(&find);
  1995.          dmt != NULL;
  1996.          dmt = (DebuggerManagedThread*)m_managedThreads.FindNext(&find))
  1997.     {
  1998.         RemoveManagedThread(dmt->GetToken() );
  1999.     }
  2000.     
  2001.     CoUninitialize();
  2002. }
  2003.  
  2004. HRESULT DebuggerShell::Init()
  2005. {
  2006.     CoInitializeEx(NULL, COINIT_MULTITHREADED);
  2007.  
  2008.     HRESULT hr = CoCreateInstance(CLSID_CorDebug, NULL, 
  2009.                                   CLSCTX_INPROC_SERVER, 
  2010.                                   IID_ICorDebug,
  2011.                                   (void **)&m_cor);
  2012.     if (FAILED(hr))
  2013.     {
  2014.         Write(L"Unable to create an ICorDebug object.\n");
  2015.         Write(L"(The most probable cause is that mscordbi.dll is not properly "
  2016.               L"registered.)\n\n");
  2017.  
  2018.         return (hr);
  2019.     }
  2020.  
  2021.     hr = m_cor->Initialize();
  2022.  
  2023.     if (FAILED(hr))
  2024.     {
  2025.         Write(L"Unable to initialize an ICorDebug object.\n");
  2026.  
  2027.         m_cor->Release();
  2028.         m_cor = NULL;
  2029.  
  2030.         return (hr);
  2031.     }
  2032.     
  2033.     ICorDebugManagedCallback *imc = GetDebuggerCallback();
  2034.  
  2035.     if (imc != NULL)
  2036.     {
  2037.         imc->AddRef();
  2038.  
  2039.         hr = m_cor->SetManagedHandler(imc);
  2040.         imc->Release();
  2041.  
  2042.         if (FAILED(hr))
  2043.             return (hr);
  2044.     }
  2045.     else
  2046.         return (E_OUTOFMEMORY);
  2047.  
  2048.     ICorDebugUnmanagedCallback *iumc = GetDebuggerUnmanagedCallback();
  2049.  
  2050.     if (iumc != NULL)
  2051.     {
  2052.         iumc->AddRef();
  2053.  
  2054.         hr = m_cor->SetUnmanagedHandler(iumc);
  2055.         iumc->Release();
  2056.  
  2057.         if (FAILED(hr))
  2058.             return (hr);
  2059.     }
  2060.     else
  2061.         return (E_OUTOFMEMORY);
  2062.     
  2063.     AddCommands();
  2064.     m_pPrompt = L"(cordbg)";
  2065.  
  2066.     // Use new so that the string is deletable.
  2067.     m_currentSourcesPath = new WCHAR[2];
  2068.     wcscpy(m_currentSourcesPath, L".");
  2069.  
  2070.     // Load the current path to any source files and the last set of
  2071.     // debugger modes from the registry.
  2072.     HKEY key;
  2073.  
  2074.     if (OpenDebuggerRegistry(&key))
  2075.     {
  2076.         WCHAR *newPath;
  2077.         if (ReadSourcesPath(key, &newPath))
  2078.         {
  2079.             delete [] m_currentSourcesPath;
  2080.             m_currentSourcesPath = newPath;
  2081.         }
  2082.  
  2083.         ReadDebuggerModes(key);
  2084.         
  2085.         CloseDebuggerRegistry(key);
  2086.     }
  2087.  
  2088.  
  2089.     m_stopEvent = CreateEventA(NULL, TRUE, FALSE, NULL);
  2090.     _ASSERTE(m_stopEvent != NULL);
  2091.  
  2092.     m_hProcessCreated = CreateEventA(NULL, FALSE, FALSE, NULL);
  2093.     _ASSERTE(m_hProcessCreated != NULL);
  2094.  
  2095.     g_pShell = this;
  2096.  
  2097.     SetConsoleCtrlHandler(InvokeDebuggerOnBreak, TRUE);
  2098.  
  2099.     return (S_OK);
  2100. }
  2101.  
  2102.  
  2103. static const WCHAR *MappingType( CorDebugMappingResult mr )
  2104. {
  2105.     switch( mr )
  2106.     {
  2107.         case MAPPING_PROLOG:
  2108.             return L"prolog";
  2109.             break;
  2110.         case MAPPING_EPILOG:
  2111.             return L"epilog";
  2112.             break;
  2113.         case MAPPING_NO_INFO:
  2114.             return L"no mapping info region";
  2115.             break;
  2116.         case MAPPING_UNMAPPED_ADDRESS:
  2117.             return L"unmapped region";
  2118.             break;
  2119.         case MAPPING_EXACT:
  2120.             return L"exactly mapped";
  2121.             break;
  2122.         case MAPPING_APPROXIMATE:
  2123.             return L"approximately mapped";
  2124.             break;
  2125.         default:
  2126.             return L"Unknown mapping";
  2127.             break;
  2128.     }
  2129. }
  2130.  
  2131. void DebuggerShell::Run(bool fNoInitialContinue)
  2132. {
  2133.     m_stop = false;
  2134.  
  2135.     HRESULT hr  = S_OK;
  2136.     
  2137.     SetCurrentThread(m_targetProcess, NULL);
  2138.  
  2139.     while (TRUE)
  2140.     {
  2141.         ResetEvent(m_stopEvent);
  2142.  
  2143.         SPEW(fprintf(stderr, "[%d] DS::R: Continuing process...\n", 
  2144.                      GetCurrentThreadId()));
  2145.  
  2146.         // Don't continue the first time of fNoInitialContinue is set
  2147.         // to true.
  2148.         if ((m_targetProcess != NULL) && !fNoInitialContinue)
  2149.         {
  2150.             ICorDebugProcess *p = m_targetProcess;
  2151.             
  2152.             p->AddRef();
  2153.             HRESULT hr = p->Continue(FALSE);
  2154.             p->Release();
  2155.         }
  2156.  
  2157.         fNoInitialContinue = false;
  2158.  
  2159.         SPEW(fprintf(stderr, "[%d] DS::R: Waiting for a callback...\n", 
  2160.                      GetCurrentThreadId()));
  2161.  
  2162.         WaitForSingleObject(m_stopEvent, INFINITE);
  2163.  
  2164.         SPEW(fprintf(stderr, "[%d] DS::R: Done waiting.\n", GetCurrentThreadId()));
  2165.  
  2166.         // If the target process has received an unmanaged event that
  2167.         // must be handled outside of the unmanaged callback, then
  2168.         // handle it now. If HandleUnmanagedEvent() returns true then
  2169.         // that means that the unmanaged event was handled in such a
  2170.         // way that the process should be continued and the user not
  2171.         // given control, so we simply continue to the top of the
  2172.         // loop.
  2173.         if (m_targetProcess && m_handleUnmanagedEvent)
  2174.             if (HandleUnmanagedEvent())
  2175.                 continue;
  2176.  
  2177.         BOOL queued;
  2178.         if (m_targetProcess == NULL
  2179.             || FAILED(m_targetProcess->HasQueuedCallbacks(NULL, &queued))
  2180.             || (!queued && m_stop))
  2181.         {
  2182.             SPEW(fprintf(stderr, "[%d] DS::R: I'm stopping now (%squeued and %sstop)...\n", 
  2183.                          GetCurrentThreadId(),
  2184.                          queued ? "" : "not ", m_stop ? "" : "not "));
  2185.             break;
  2186.         }
  2187.  
  2188.         SPEW(fprintf(stderr, "[%d] DS::R: I'm gonna do it again (%squeued and %sstop)...\n",
  2189.                      GetCurrentThreadId(),
  2190.                      queued ? "" : "not ", m_stop ? "" : "not "));
  2191.     }
  2192.  
  2193.     if (m_currentThread != NULL)
  2194.     {
  2195.         SetDefaultFrame();
  2196.  
  2197.         if (!m_silentTracing) 
  2198.         {
  2199.             ULONG32 IP;
  2200.             CorDebugMappingResult map;
  2201.  
  2202.             if ( m_currentFrame != NULL &&
  2203.                  SUCCEEDED( m_currentFrame->GetIP( &IP, &map ) ) )
  2204.             {
  2205.  
  2206.                 if (map & ~(MAPPING_APPROXIMATE | MAPPING_EXACT) )
  2207.                 {
  2208.                     if ((map != MAPPING_EPILOG) || (m_rgfActiveModes & DSM_UNMAPPED_STOP_EPILOG))
  2209.                     {
  2210.                         g_pShell->Write( L"Source not available when in the %s"
  2211.                                          L" of a function(offset 0x%x)\n",
  2212.                                          MappingType(map),IP);
  2213.                         g_pShell->m_showSource = false;
  2214.                     }
  2215.                 }
  2216.  
  2217.             }
  2218.         
  2219.             PrintThreadPrefix(m_currentThread);
  2220.             Write( L"\n" );
  2221.  
  2222.             if (! (m_showSource 
  2223.                    ? PrintCurrentSourceLine(0) 
  2224.                    : PrintCurrentInstruction(0)))
  2225.                 PrintThreadState(m_currentThread);
  2226.         }
  2227.     }
  2228.  
  2229.     //this only has an effect when m_targetProcess == NULL
  2230.     // (ie, the target process has exited)
  2231.     m_lastStepper = NULL;
  2232. }
  2233.  
  2234. void DebuggerShell::Kill()
  2235. {
  2236.     if (m_targetProcess != NULL)
  2237.     {
  2238.         HANDLE h;
  2239.  
  2240.         HRESULT hr = m_targetProcess->GetHandle(&h);
  2241.  
  2242.         Write(L"Terminating current process...\n");
  2243.  
  2244.         ResetEvent(m_stopEvent);
  2245.         
  2246.         m_targetProcess->Terminate(0);
  2247.  
  2248.         SetCurrentThread(NULL, NULL);
  2249.  
  2250.         // Don't call Run. There is no need to Continue from calling
  2251.         // ICorDebugProcess::Terminate, and ExitProcess will be called
  2252.         // automatically. Instead, we simply wait for ExitProcess to
  2253.         // get called before going back to the command prompt.
  2254.         WaitForSingleObject(m_stopEvent, INFINITE);
  2255.     }
  2256.  
  2257.     ClearDebuggeeState();
  2258. }
  2259.  
  2260. // AsyncStop gets called by the main thread (the one that handles the
  2261. // command prompt) to stop an <appdomain> asynchronously.
  2262. HRESULT DebuggerShell::AsyncStop(ICorDebugController *controller, 
  2263.                                  DWORD dwTimeout)
  2264. {
  2265.     return controller->Stop(dwTimeout);
  2266. }
  2267.  
  2268. // Stop gets used by callbacks to tell the main loop (the one that
  2269. // called Run()) that we want to stop running now. c.f. AsyncStop
  2270. void DebuggerShell::Stop(ICorDebugController *controller, 
  2271.                          ICorDebugThread *thread,
  2272.                          DebuggerUnmanagedThread *unmanagedThread)
  2273. {
  2274.     //
  2275.     // Don't stop for any process other than the target.
  2276.     //
  2277.     ICorDebugProcess *process = NULL;
  2278.     HRESULT hr = S_OK;
  2279.     
  2280.     if (controller != NULL)
  2281.         hr = controller->QueryInterface(IID_ICorDebugProcess, 
  2282.                                         (void **)&process);
  2283.  
  2284.     if (hr==E_NOINTERFACE )
  2285.     {
  2286.         ICorDebugAppDomain *appDomain = NULL;
  2287.         
  2288.         _ASSERTE(process == NULL);
  2289.  
  2290.         hr = controller->QueryInterface(IID_ICorDebugAppDomain,
  2291.                                         (void **)&appDomain);
  2292.         _ASSERTE(!FAILED(hr)); 
  2293.         
  2294.         hr = appDomain->GetProcess(&process);
  2295.         
  2296.         _ASSERTE(!FAILED(hr)); 
  2297.         _ASSERTE(NULL != process); 
  2298.  
  2299.         RELEASE(appDomain);
  2300.     }
  2301.     if (FAILED(hr))
  2302.         g_pShell->ReportError(hr);
  2303.     
  2304.     if (!FAILED(hr) &&
  2305.         process != m_targetProcess && 
  2306.         process != NULL)
  2307.     {
  2308.         HRESULT hr = controller->Continue(FALSE);
  2309.         if (FAILED(hr))
  2310.             g_pShell->ReportError(hr);
  2311.     }
  2312.     else
  2313.     {
  2314.         m_stop = true;
  2315.         SetCurrentThread(process, thread, unmanagedThread);
  2316.         SetEvent(m_stopEvent);
  2317.     }
  2318.  
  2319.     if (NULL !=process)
  2320.         RELEASE(process);
  2321. }
  2322.  
  2323. void DebuggerShell::Continue(ICorDebugController *controller,
  2324.                              ICorDebugThread *thread,
  2325.                              DebuggerUnmanagedThread *unmanagedThread,
  2326.                              BOOL fIsOutOfBand)
  2327. {
  2328.     HRESULT hr = S_OK;
  2329.     
  2330.     if (!m_stop)
  2331.     {
  2332.         hr = controller->Continue(fIsOutOfBand);
  2333.  
  2334.         if (FAILED(hr) && !m_stop)
  2335.             g_pShell->ReportError(hr);
  2336.     }
  2337.     else
  2338.     {
  2339.         //
  2340.         // Just go ahead and continue from any events on other processes.
  2341.         //
  2342.         ICorDebugProcess *process = NULL;
  2343.         HRESULT hr = S_OK;
  2344.         hr = controller->QueryInterface(IID_ICorDebugProcess, 
  2345.                                          (void **)&process);
  2346.  
  2347.         if (hr==E_NOINTERFACE ||
  2348.             process == NULL)
  2349.         {
  2350.             ICorDebugAppDomain *appDomain = NULL;
  2351.             hr = controller->QueryInterface(IID_ICorDebugAppDomain,
  2352.                                             (void **)&appDomain);
  2353.             _ASSERTE(!FAILED(hr)); 
  2354.             
  2355.             hr = appDomain->GetProcess(&process);
  2356.             _ASSERTE(!FAILED(hr)); 
  2357.             _ASSERTE(NULL != process); 
  2358.  
  2359.             RELEASE(appDomain);
  2360.         }
  2361.  
  2362.         if (!FAILED(hr) && 
  2363.             process != m_targetProcess && 
  2364.             process != NULL)
  2365.         {
  2366.             HRESULT hr = controller->Continue(FALSE);
  2367.  
  2368.             if (FAILED(hr))
  2369.                 g_pShell->ReportError(hr);
  2370.         }
  2371.         else
  2372.         {
  2373.             SetEvent(m_stopEvent);
  2374.         }
  2375.         
  2376.         RELEASE(process);
  2377.     }
  2378. }
  2379.  
  2380. void DebuggerShell::Interrupt()
  2381. {
  2382.     HRESULT hr = m_targetProcess->Stop(INFINITE);
  2383.  
  2384.     if (FAILED(hr))
  2385.     {
  2386.         Write(L"\nError stopping process:  ", hr);
  2387.         ReportError(hr);
  2388.     }
  2389.     else
  2390.         Stop(m_targetProcess, NULL);
  2391. }
  2392.  
  2393. void DebuggerShell::SetTargetProcess(ICorDebugProcess *pProcess)
  2394. {
  2395.     if (pProcess != m_targetProcess)
  2396.     {
  2397.         if (m_targetProcess != NULL)
  2398.             RELEASE(m_targetProcess);
  2399.  
  2400.         m_targetProcess = pProcess;
  2401.  
  2402.         if (pProcess != NULL)
  2403.             pProcess->AddRef();
  2404.  
  2405.         //
  2406.         // If we're done with a process, remove all of the modules.
  2407.         // This will clean up if we miss some unload module events.
  2408.         //
  2409.  
  2410.         if (m_targetProcess == NULL)
  2411.         {
  2412.             g_pShell->m_modules.RemoveAll();
  2413.             m_targetProcessHandledFirstException = false;
  2414.         }
  2415.     }
  2416. }
  2417.  
  2418. void DebuggerShell::SetCurrentThread(ICorDebugProcess *pProcess, 
  2419.                                      ICorDebugThread *pThread,
  2420.                                      DebuggerUnmanagedThread *pUnmanagedThread)
  2421. {
  2422.     if (pThread != NULL && pUnmanagedThread == NULL)
  2423.     {
  2424.         //
  2425.         // Lookup the corresponding unmanaged thread
  2426.         // 
  2427.  
  2428.         DWORD threadID;
  2429.         HRESULT hr;
  2430.     
  2431.         hr = pThread->GetID(&threadID);
  2432.         if (SUCCEEDED(hr))
  2433.         {
  2434.             pUnmanagedThread = 
  2435.               (DebuggerUnmanagedThread*) m_unmanagedThreads.GetBase(threadID);
  2436.         }
  2437.     }
  2438.     else if (pUnmanagedThread != NULL && pThread == NULL)
  2439.     {
  2440.         //
  2441.         // Lookup the corresponding managed thread
  2442.         //
  2443.  
  2444.         HRESULT hr;
  2445.  
  2446.         hr = pProcess->GetThread(pUnmanagedThread->GetId(), &pThread);
  2447.         if (pThread != NULL)
  2448.             RELEASE(pThread);
  2449.     }
  2450.  
  2451.     if (pProcess != m_currentProcess)
  2452.     {
  2453.         if (m_currentProcess != NULL)
  2454.             m_currentProcess->Release();
  2455.  
  2456.         m_currentProcess = pProcess;
  2457.  
  2458.         if (pProcess != NULL)
  2459.             pProcess->AddRef();
  2460.     }
  2461.  
  2462.     if (pThread != m_currentThread)
  2463.     {
  2464.         if (m_currentThread != NULL)
  2465.             m_currentThread->Release();
  2466.  
  2467.         m_currentThread = pThread;
  2468.  
  2469.         if (pThread != NULL)
  2470.             pThread->AddRef();
  2471.     }
  2472.  
  2473.     m_currentUnmanagedThread = pUnmanagedThread;
  2474.  
  2475.     SetCurrentChain(NULL);
  2476.     SetCurrentFrame(NULL);
  2477. }
  2478.  
  2479. void DebuggerShell::SetCurrentChain(ICorDebugChain *chain)
  2480. {
  2481.     if (chain != m_currentChain)
  2482.     {
  2483.         if (m_currentChain != NULL)
  2484.             m_currentChain->Release();
  2485.  
  2486.         m_currentChain = chain;
  2487.  
  2488.         if (chain != NULL)
  2489.             chain->AddRef();
  2490.     }
  2491. }
  2492.  
  2493. void DebuggerShell::SetCurrentFrame(ICorDebugFrame *frame)
  2494. {
  2495.     if (frame != m_rawCurrentFrame)
  2496.     {
  2497.         if (m_rawCurrentFrame != NULL)
  2498.             m_rawCurrentFrame->Release();
  2499.  
  2500.         if (m_currentFrame != NULL)
  2501.             m_currentFrame->Release();
  2502.  
  2503.         m_rawCurrentFrame = frame;
  2504.  
  2505.         if (frame != NULL)
  2506.         {
  2507.             frame->AddRef();
  2508.  
  2509.             if (FAILED(frame->QueryInterface(IID_ICorDebugILFrame, 
  2510.                                              (void **) &m_currentFrame)))
  2511.                 m_currentFrame = NULL;
  2512.         }
  2513.         else
  2514.             m_currentFrame = NULL;
  2515.     }
  2516. }
  2517.  
  2518. void DebuggerShell::SetDefaultFrame()
  2519. {
  2520.     if (m_currentThread != NULL)
  2521.     {
  2522.         ICorDebugChain *ichain;
  2523.         HRESULT hr = m_currentThread->GetActiveChain(&ichain);
  2524.  
  2525.         if (FAILED(hr))
  2526.         {
  2527.             g_pShell->ReportError(hr);
  2528.             return;
  2529.         }
  2530.  
  2531.         SetCurrentChain(ichain);
  2532.         if (ichain != NULL)
  2533.         {
  2534.             RELEASE(ichain);
  2535.  
  2536.             ICorDebugFrame *iframe;
  2537.  
  2538.             hr = m_currentThread->GetActiveFrame(&iframe);
  2539.  
  2540.             if (FAILED(hr))
  2541.             {
  2542.                 g_pShell->ReportError(hr);
  2543.                 return;
  2544.             }
  2545.  
  2546.             SetCurrentFrame(iframe);
  2547.             if (iframe != NULL)
  2548.                 RELEASE(iframe);
  2549.         }
  2550.     }
  2551. }
  2552.  
  2553. static const WCHAR WcharFromDebugState(CorDebugThreadState debugState)
  2554. {
  2555.     WCHAR sz;
  2556.  
  2557.     switch( debugState )
  2558.     {
  2559.         case THREAD_RUN:
  2560.             sz = L'R';
  2561.             break;
  2562.         case THREAD_SUSPEND:
  2563.             sz = L'S';
  2564.             break;
  2565.         default:
  2566.             _ASSERTE( !"WcharFromDebugState given an invalid value" );
  2567.             sz = L'?';
  2568.             break;
  2569.     }
  2570.  
  2571.     return sz;
  2572. }
  2573.  
  2574. HRESULT DebuggerShell::PrintThreadState(ICorDebugThread *thread)
  2575. {
  2576.     DWORD threadID;
  2577.     HRESULT hr;
  2578.  
  2579.     hr = thread->GetID(&threadID);
  2580.  
  2581.     if (FAILED(hr))
  2582.         return hr;
  2583.  
  2584.     Write(L"Thread 0x%x", threadID);
  2585.  
  2586.     CorDebugThreadState ds;
  2587.     if( !FAILED(thread->GetDebugState(&ds)))
  2588.     {
  2589.         Write(L" %c ", WcharFromDebugState(ds));
  2590.     }
  2591.     else
  2592.     {
  2593.         Write(L" - ");
  2594.     }
  2595.     
  2596.     ICorDebugILFrame* ilframe = NULL;
  2597.     ICorDebugNativeFrame* nativeframe = NULL;
  2598.  
  2599.     if (thread == m_currentThread)
  2600.     {
  2601.         ilframe = m_currentFrame;
  2602.         if (ilframe != NULL)
  2603.             ilframe->AddRef();
  2604.         if (m_rawCurrentFrame != NULL )
  2605.             m_rawCurrentFrame->QueryInterface( IID_ICorDebugNativeFrame,
  2606.                                 (void **)&nativeframe);
  2607.     }
  2608.     else
  2609.     {
  2610.         ICorDebugFrame *iframe;
  2611.         hr = thread->GetActiveFrame(&iframe);
  2612.         if (FAILED(hr))
  2613.             return hr;
  2614.  
  2615.         if (iframe != NULL)
  2616.         {
  2617.             hr = iframe->QueryInterface(IID_ICorDebugILFrame, 
  2618.                                         (void **) &ilframe);
  2619.             if (FAILED(hr))
  2620.                 ilframe = NULL;
  2621.             
  2622.             hr = iframe->QueryInterface( IID_ICorDebugNativeFrame,
  2623.                                     (void **)&nativeframe);
  2624.             RELEASE(iframe);
  2625.             if (FAILED(hr))
  2626.                 return hr;
  2627.         }
  2628.  
  2629.         if (FAILED(hr))
  2630.             g_pShell->ReportError(hr);
  2631.     }
  2632.  
  2633.     if ( nativeframe != NULL)
  2634.     {
  2635.         DWORD id;
  2636.         HRESULT hr = thread->GetID(&id);
  2637.  
  2638.         if (SUCCEEDED(hr))
  2639.         {
  2640.             ICorDebugCode *icode;
  2641.             if (ilframe != NULL )
  2642.                 hr = ilframe->GetCode(&icode);
  2643.             else
  2644.                 hr = nativeframe->GetCode( &icode );
  2645.  
  2646.             if (SUCCEEDED(hr))
  2647.             {
  2648.                 ICorDebugFunction *ifunction;
  2649.                 hr = icode->GetFunction(&ifunction);
  2650.  
  2651.                 if (SUCCEEDED(hr))
  2652.                 {
  2653.                     DebuggerFunction *function;
  2654.                     function = DebuggerFunction::FromCorDebug(ifunction);
  2655.                     _ASSERTE(function != NULL);
  2656.             
  2657.                     ULONG32 ip = 0;
  2658.                     ULONG32 nativeIp = 0;
  2659.                     bool fILIP = false;
  2660.                     if (nativeframe != NULL )
  2661.                     {
  2662.                         hr = nativeframe->GetIP(&nativeIp);
  2663.                     }
  2664.                     if (ilframe != NULL && !FAILED( hr ) )
  2665.                     {
  2666.                         CorDebugMappingResult mappingResult;
  2667.                         if (!FAILED( ilframe->GetIP(&ip, &mappingResult) ) )
  2668.                             fILIP = true;
  2669.                     }
  2670.  
  2671.                     if (SUCCEEDED(hr))
  2672.                     {
  2673.                         DebuggerSourceFile *sf = NULL;
  2674.                         unsigned int lineNumber = 0;
  2675.  
  2676.                         if (fILIP)
  2677.                             hr = function->FindLineFromIP(ip, &sf,
  2678.                                                           &lineNumber);
  2679.  
  2680.                         if (SUCCEEDED(hr))
  2681.                         {
  2682.                             Write(L" at %s::%s", function->m_className, function->m_name);
  2683.                     
  2684.                             Write(L" +%.4x", nativeIp);
  2685.                             if (fILIP
  2686.                                 && m_rgfActiveModes & DSM_IL_NATIVE_PRINTING)
  2687.                                 Write( L"[native] +%.4x[IL]", ip );
  2688.  
  2689.                             if (sf != NULL)
  2690.                                 Write(L" in %s:%d", sf->GetName(), lineNumber);
  2691.                         }
  2692.                         else
  2693.                             g_pShell->ReportError(hr);
  2694.                     }
  2695.                     else
  2696.                         g_pShell->ReportError(hr);
  2697.  
  2698.                     RELEASE(ifunction);
  2699.                 }
  2700.                 else
  2701.                     g_pShell->ReportError(hr);
  2702.  
  2703.                 RELEASE(icode);
  2704.             }
  2705.             else
  2706.                 g_pShell->ReportError(hr);
  2707.         }
  2708.         else
  2709.             g_pShell->ReportError(hr);
  2710.  
  2711.         if (ilframe)
  2712.             RELEASE(ilframe);
  2713.     }
  2714.     else
  2715.     {
  2716.         //
  2717.         // See if we at least have a current chain
  2718.         //
  2719.  
  2720.         ICorDebugChain *ichain = NULL;
  2721.  
  2722.         if (thread == m_currentThread)
  2723.         {
  2724.             ichain = m_currentChain;
  2725.             if (ichain != NULL)
  2726.                 ichain->AddRef();
  2727.         }
  2728.         else
  2729.         {
  2730.             hr = thread->GetActiveChain(&ichain);
  2731.  
  2732.             if (FAILED(hr))
  2733.                 return hr;
  2734.         }
  2735.  
  2736.         if (ichain != NULL)
  2737.         {
  2738.             BOOL isManaged;
  2739.             HRESULT hr = ichain->IsManaged(&isManaged);
  2740.  
  2741.             if (FAILED(hr))
  2742.                 return hr;
  2743.  
  2744.             if (isManaged)
  2745.             {
  2746.                 // 
  2747.                 // Just print the chain - it has no frames so will
  2748.                 // be one line
  2749.                 //
  2750.  
  2751.                 PrintChain(ichain);
  2752.             }
  2753.             else
  2754.             {
  2755.                 //
  2756.                 // Print the top line of the stack trace
  2757.                 //
  2758.  
  2759.                 ICorDebugRegisterSet *pRegisters;
  2760.  
  2761.                 hr = ichain->GetRegisterSet(&pRegisters);
  2762.                 if (FAILED(hr))
  2763.                     return hr;
  2764.  
  2765.                 CORDB_REGISTER ip;
  2766.  
  2767.                 hr = pRegisters->GetRegisters(1<<REGISTER_INSTRUCTION_POINTER,
  2768.                                               1, &ip);
  2769.                 pRegisters->Release();
  2770.                 if (FAILED(hr))
  2771.                     return hr;
  2772.  
  2773.                 ICorDebugProcess *iprocess;
  2774.                 hr = thread->GetProcess(&iprocess);
  2775.                 if (FAILED(hr))
  2776.                     return hr;
  2777.  
  2778.                 HANDLE hProcess;
  2779.                 hr = iprocess->GetHandle(&hProcess);
  2780.                 RELEASE(iprocess);
  2781.                 if (FAILED(hr))
  2782.                     return hr;
  2783.  
  2784.                 PrintUnmanagedStackFrame(hProcess, ip);
  2785.             }
  2786.         
  2787.             ichain->Release();
  2788.         }
  2789.         else
  2790.             Write(L" <no information available>");
  2791.     }
  2792.     
  2793.     if (NULL != nativeframe)
  2794.         RELEASE( nativeframe);
  2795.     Write(L"\n");
  2796.  
  2797.     return S_OK;
  2798. }
  2799.  
  2800. HRESULT DebuggerShell::PrintChain(ICorDebugChain *chain, 
  2801.                                   int *frameIndex,
  2802.                                   int *iNumFramesToShow)
  2803. {
  2804.     ULONG count;
  2805.     BOOL isManaged;
  2806.     int frameCount = 0;
  2807.     int iNumFrames = 1000;
  2808.  
  2809.     if (frameIndex != NULL)
  2810.         frameCount = *frameIndex;
  2811.  
  2812.     if (iNumFramesToShow != NULL)
  2813.         iNumFrames = *iNumFramesToShow;
  2814.  
  2815.     // Determined whether or not the chain is managed
  2816.     HRESULT hr = chain->IsManaged(&isManaged);
  2817.  
  2818.     if (FAILED(hr))
  2819.         return hr;
  2820.  
  2821.     // Chain is managed, so information can be displayed
  2822.     if (isManaged)
  2823.     {
  2824.         // Enumerate every frame in the chain
  2825.         ICorDebugFrameEnum *fe;
  2826.         hr = chain->EnumerateFrames(&fe);
  2827.  
  2828.         if (FAILED(hr))
  2829.             return hr;
  2830.  
  2831.         // Get the first frame in the enumeration
  2832.         ICorDebugFrame *iframe;
  2833.         hr = fe->Next(1, &iframe, &count);
  2834.  
  2835.         if (FAILED(hr))
  2836.             return hr;
  2837.  
  2838.         // Display properties for each frame
  2839.         while ( (count == 1) && (iNumFrames-- > 0))
  2840.         {
  2841.             // Indicate the top frame
  2842.             if (chain == m_currentChain && iframe == m_rawCurrentFrame)
  2843.                 Write(L"%d)* ", frameCount++);
  2844.             else
  2845.                 Write(L"%d)  ", frameCount++);
  2846.  
  2847.             PrintFrame(iframe);
  2848.             RELEASE(iframe);
  2849.  
  2850.             // Get the next frame. We don't stop if printing a frame
  2851.             // fails for some reason.
  2852.             hr = fe->Next(1, &iframe, &count);
  2853.  
  2854.             if (FAILED(hr))
  2855.             {
  2856.                 RELEASE(fe);
  2857.                 return hr;
  2858.             }
  2859.         }
  2860.  
  2861.         // Done with current frame
  2862.         RELEASE(fe);
  2863.     }
  2864.     else
  2865.     {
  2866.         CORDB_ADDRESS stackStart, stackEnd;
  2867.  
  2868.         ICorDebugThread *ithread;
  2869.         hr = chain->GetThread(&ithread);
  2870.         if (FAILED(hr))
  2871.             return hr;
  2872.                 
  2873.         hr = chain->GetStackRange(&stackStart, &stackEnd);
  2874.         if (FAILED(hr))
  2875.             return hr;
  2876.  
  2877.         ICorDebugRegisterSet *pRegisters;
  2878.  
  2879.         hr = chain->GetRegisterSet(&pRegisters);
  2880.         if (FAILED(hr))
  2881.             return hr;
  2882.  
  2883.         CORDB_REGISTER registers[3];
  2884.  
  2885.         hr = pRegisters->GetRegisters((1<<REGISTER_INSTRUCTION_POINTER)
  2886.                                       | (1<<REGISTER_STACK_POINTER)
  2887.                                       | (1<<REGISTER_FRAME_POINTER),
  2888.                                       3, registers);
  2889.         
  2890.         if (FAILED(hr))
  2891.             return hr;
  2892.  
  2893.         pRegisters->Release();
  2894.  
  2895.         HANDLE hThread;
  2896.         hr = ithread->GetHandle(&hThread);
  2897.         if (FAILED(hr))
  2898.             return hr;
  2899.  
  2900.         ICorDebugProcess *iprocess;
  2901.         hr = ithread->GetProcess(&iprocess);
  2902.         RELEASE(ithread);
  2903.         if (FAILED(hr))
  2904.             return hr;
  2905.  
  2906.         HANDLE hProcess;
  2907.         hr = iprocess->GetHandle(&hProcess);
  2908.         RELEASE(iprocess);
  2909.         if (FAILED(hr))
  2910.             return hr;
  2911.  
  2912.         if (chain == m_currentChain )
  2913.             Write(L"* ");
  2914.  
  2915.         TraceUnmanagedStack(hProcess, hThread, 
  2916.                             registers[REGISTER_INSTRUCTION_POINTER],
  2917.                             registers[REGISTER_FRAME_POINTER],
  2918.                             registers[REGISTER_STACK_POINTER],
  2919.                             stackEnd);
  2920.     }
  2921.  
  2922.     CorDebugChainReason reason;
  2923.  
  2924.     // Get & print chain's reason
  2925.     hr = chain->GetReason(&reason);
  2926.  
  2927.     if (FAILED(hr))
  2928.         return hr;
  2929.  
  2930.     LPWSTR reasonString = NULL;
  2931.  
  2932.     switch (reason)
  2933.     {
  2934.     case CHAIN_PROCESS_START:
  2935.     case CHAIN_THREAD_START:
  2936.         break;
  2937.  
  2938.     case CHAIN_ENTER_MANAGED:
  2939.         reasonString = L"Managed transition";
  2940.         break;
  2941.  
  2942.     case CHAIN_ENTER_UNMANAGED:
  2943.         reasonString = L"Unmanaged transition";
  2944.         break;
  2945.  
  2946.     case CHAIN_CLASS_INIT:
  2947.         reasonString = L"Class initialization";
  2948.         break;
  2949.  
  2950.     case CHAIN_DEBUGGER_EVAL:
  2951.         reasonString = L"Debugger evaluation";
  2952.         break;
  2953.  
  2954.     case CHAIN_EXCEPTION_FILTER:
  2955.         reasonString = L"Exception filter";
  2956.         break;
  2957.  
  2958.     case CHAIN_SECURITY:
  2959.         reasonString = L"Security";
  2960.         break;
  2961.  
  2962.     case CHAIN_CONTEXT_POLICY:
  2963.         reasonString = L"Context policy";
  2964.         break;
  2965.  
  2966.     case CHAIN_CONTEXT_SWITCH:
  2967.         reasonString = L"Context switch";
  2968.         break;
  2969.  
  2970.     case CHAIN_INTERCEPTION:
  2971.         reasonString = L"Interception";
  2972.         break;
  2973.  
  2974.     case CHAIN_FUNC_EVAL:
  2975.         reasonString = L"Function Evaluation";
  2976.         break;
  2977.  
  2978.     default:
  2979.         reasonString = NULL;
  2980.     }
  2981.  
  2982.     if (reasonString != NULL)
  2983.         Write(L"--- %s ---\n", reasonString);
  2984.  
  2985.     if (frameIndex != NULL)
  2986.         *frameIndex = frameCount;
  2987.  
  2988.     if (iNumFramesToShow != NULL)
  2989.         *iNumFramesToShow = iNumFrames;
  2990.  
  2991.     return S_OK;
  2992. }
  2993.  
  2994. HRESULT DebuggerShell::PrintFrame(ICorDebugFrame *frame)
  2995. {
  2996.     ICorDebugILFrame       *ilframe = NULL;
  2997.     ICorDebugCode          *icode = NULL;
  2998.     ICorDebugFunction      *ifunction = NULL;
  2999.     ICorDebugNativeFrame   *icdNativeFrame = NULL;
  3000.  
  3001.     DebuggerFunction       *function = NULL;
  3002.     unsigned int            j;
  3003.     DebuggerSourceFile     *sf = NULL;
  3004.     unsigned int            lineNumber = 0;
  3005.     bool                    fILIP = false;
  3006.     ULONG32                 nativeIp = 0;
  3007.     WCHAR                   wsz[40];
  3008.  
  3009.     // Get the native frame for the current frame
  3010.     HRESULT hr = frame->QueryInterface(IID_ICorDebugNativeFrame,
  3011.                                        (void **)&icdNativeFrame);
  3012.     
  3013.     if (FAILED(hr))
  3014.     {
  3015.         Write(L"[Unable to obtain any frame information]");
  3016.         goto LExit;
  3017.     }
  3018.  
  3019.     // Get the IL frame for the current frame
  3020.     hr = frame->QueryInterface(IID_ICorDebugILFrame, 
  3021.                                (void **) &ilframe);
  3022.     
  3023.     if (FAILED(hr))
  3024.         ilframe = NULL;
  3025.  
  3026.     // Get the code for the frame
  3027.     if (ilframe != NULL )
  3028.         hr = ilframe->GetCode(&icode);
  3029.     else
  3030.         hr = icdNativeFrame->GetCode(&icode);
  3031.  
  3032.     if (FAILED(hr))
  3033.     {
  3034.         Write(L"[Unable to obtain any code information]");
  3035.         goto LExit;
  3036.     }
  3037.                     
  3038.     // Get the function for the code
  3039.     hr = icode->GetFunction(&ifunction);
  3040.     
  3041.     if (FAILED(hr))
  3042.     {
  3043.         Write(L"[Unable to obtain any function information]");
  3044.         goto LExit;
  3045.     }
  3046.                     
  3047.     // Get the DebuggerFunction for the function iface
  3048.     function = DebuggerFunction::FromCorDebug(ifunction);
  3049.     _ASSERTE(function);
  3050.     
  3051.     // Get the IP for the current frame
  3052.     ULONG32 ip;
  3053.     
  3054.     if (ilframe != NULL)
  3055.     {
  3056.         CorDebugMappingResult mappingResult;
  3057.         
  3058.         hr = ilframe->GetIP(&ip, &mappingResult);
  3059.  
  3060.         // Find the source line for the IP
  3061.         hr = function->FindLineFromIP(ip, &sf, &lineNumber);
  3062.  
  3063.         if (FAILED(hr))
  3064.             ip = 0;
  3065.         else
  3066.             fILIP = true;
  3067.     }
  3068.     
  3069.     // If the module names are desired, then include the name in front of
  3070.     // the class info ntsd-style.
  3071.     if (m_rgfActiveModes & DSM_SHOW_MODULES_IN_STACK_TRACE)
  3072.     {
  3073.         WCHAR       *szModule;
  3074.         WCHAR       rcModule[_MAX_PATH];
  3075.  
  3076.         DebuggerModule *module = function->GetModule();
  3077.         szModule = module->GetName();
  3078.         _wsplitpath(szModule, NULL, NULL, rcModule, NULL);
  3079.         Write(L"%s!", rcModule);
  3080.     }
  3081.     
  3082.     // Write out the class and method for the current IP
  3083.     Write(L"%s%s::%s", 
  3084.           function->GetNamespaceName(),
  3085.           function->GetClassName(), 
  3086.           function->GetName());
  3087.  
  3088.     // Print out the funtion's source file, line and start addr
  3089.     if (!FAILED(icdNativeFrame->GetIP(&nativeIp)))
  3090.         Write(L" +%.4x", nativeIp);
  3091.  
  3092.     if ((m_rgfActiveModes & DSM_IL_NATIVE_PRINTING) && fILIP == true)
  3093.         Write( L"[native] +%.4x[IL]", ip);
  3094.  
  3095.     if (lineNumber > 0)
  3096.     {
  3097.         if (sf->GetPath())
  3098.             Write(L" in %s:%d", sf->GetPath(), lineNumber);
  3099.         else if (sf->GetName())
  3100.             Write(L" in %s:%d", sf->GetName(), lineNumber);
  3101.         else
  3102.             Write(L" in %s:%d", L"<UnknownFilename>", lineNumber);
  3103.     }
  3104.     else
  3105.         Write(L" [no source information available]");
  3106.  
  3107.     // if currently associated source file does not have 
  3108.     // lineNumber number of lines, warn the user
  3109.     if (lineNumber > 0)
  3110.     {
  3111.         if (sf != NULL)
  3112.         {
  3113.             if (sf->GetPath() && (sf->TotalLines() < lineNumber))
  3114.                 Write(L"\tWARNING: The currently associated source file has only %d lines."
  3115.                         , sf->TotalLines());
  3116.         }
  3117.     }
  3118.  
  3119.     if (m_rgfActiveModes & DSM_SHOW_ARGS_IN_STACK_TRACE)
  3120.     {
  3121.         // Now print out the arguments for the method
  3122.         ICorDebugILFrame *ilf = NULL;
  3123.  
  3124.         hr = frame->QueryInterface(IID_ICorDebugILFrame, (void **)&ilf);
  3125.  
  3126.         if (FAILED(hr))
  3127.             goto LExit;
  3128.  
  3129.         ICorDebugValueEnum *pArgs = NULL;
  3130.  
  3131.         hr = ilf->EnumerateArguments(&pArgs);
  3132.  
  3133.         if (!SUCCEEDED(hr))
  3134.             goto LExit;
  3135.         
  3136.         RELEASE(ilf);
  3137.         ilf = NULL;
  3138.  
  3139.         ULONG argCount;
  3140.  
  3141.         hr = pArgs->GetCount(&argCount);
  3142.  
  3143.         if (!SUCCEEDED(hr))
  3144.             goto LExit;
  3145.         
  3146. #ifdef _DEBUG
  3147.         bool fVarArgs = false;
  3148.         PCCOR_SIGNATURE sig = function->GetSignature();
  3149.         ULONG callConv = CorSigUncompressCallingConv(sig);
  3150.  
  3151.         if ((callConv & IMAGE_CEE_CS_CALLCONV_MASK) &
  3152.             IMAGE_CEE_CS_CALLCONV_VARARG)
  3153.             fVarArgs = true;
  3154. #endif //_DEBUG
  3155.  
  3156.         ULONG cTemp = function->GetArgumentCount();
  3157.  
  3158.         // Var Args functions have call-site-specific numbers of
  3159.         // arguments
  3160.         _ASSERTE( argCount == cTemp || fVarArgs);
  3161.  
  3162.         ICorDebugValue *ival;
  3163.         ULONG celtFetched = 0;
  3164.  
  3165.         // Print out each argument first
  3166.         // Avoid printing "this" in arg list for static methods
  3167.         if (function->IsStatic())
  3168.         {
  3169.             j = 0;
  3170.         }
  3171.         else
  3172.         {
  3173.             j = 1;
  3174.  
  3175.             hr = pArgs->Next(1, &ival,&celtFetched);
  3176.         }
  3177.  
  3178.         LPWSTR nameWsz;
  3179.         for (; j < argCount; j++)
  3180.         {
  3181.             DebuggerVarInfo* arg = function->GetArgumentAt(j);
  3182.  
  3183.             Write(L"\n\t\t");
  3184.             if (arg != NULL)
  3185.             {
  3186.                 MAKE_WIDEPTR_FROMUTF8(nameW, arg->name);
  3187.                 nameWsz = nameW;
  3188.             }
  3189.             else
  3190.             {
  3191.                 wsprintf( wsz, L"Arg%d", j );
  3192.                 nameWsz = wsz;
  3193.             }
  3194.  
  3195.             // Get the field value
  3196.             hr = pArgs->Next(1, &ival,&celtFetched);
  3197.  
  3198.             // If successful, print the variable
  3199.             if (SUCCEEDED(hr) && celtFetched==1)
  3200.             {
  3201.                 //@TODO: Remove when DbgMeta becomes Unicode
  3202.  
  3203.                 PrintVariable(nameWsz, ival, 0, FALSE);
  3204.             }
  3205.  
  3206.             // Otherwise, indicate that it is unavailable
  3207.             else
  3208.                 Write(L"%s = <unavailable>", nameWsz);
  3209.         }
  3210.  
  3211.         pArgs->Release();
  3212.         pArgs = NULL;
  3213.     }
  3214.  
  3215.  LExit:
  3216.     Write(L"\n");
  3217.  
  3218.     // Clean up
  3219.     if (icdNativeFrame != NULL )
  3220.         RELEASE( icdNativeFrame);
  3221.  
  3222.     if (icode != NULL )
  3223.         RELEASE(icode);
  3224.  
  3225.     if (ilframe != NULL )
  3226.         RELEASE(ilframe);
  3227.  
  3228.     if (ifunction != NULL )
  3229.         RELEASE(ifunction);
  3230.  
  3231.     return hr;
  3232. }
  3233.  
  3234. DebuggerBreakpoint *DebuggerShell::FindBreakpoint(SIZE_T id)
  3235. {
  3236.     DebuggerBreakpoint *b = m_breakpoints;
  3237.  
  3238.     while (b != NULL)
  3239.     {
  3240.         if (b->m_id == id)
  3241.             return (b);
  3242.  
  3243.         b = b->m_next;
  3244.     }
  3245.  
  3246.     return (NULL);
  3247. }
  3248.  
  3249.  
  3250. void DebuggerShell::RemoveAllBreakpoints()
  3251. {
  3252.     while (m_breakpoints != NULL)
  3253.     {
  3254.         delete m_breakpoints;
  3255.     }
  3256. }
  3257.  
  3258. void DebuggerShell::OnActivateBreakpoint(DebuggerBreakpoint *pb)
  3259. {
  3260. }
  3261.  
  3262. void DebuggerShell::OnDeactivateBreakpoint(DebuggerBreakpoint *pb)
  3263. {
  3264. }
  3265.  
  3266. void DebuggerShell::OnBindBreakpoint(DebuggerBreakpoint *pb, DebuggerModule *pm)
  3267. {
  3268.     Write(L"Breakpoint #%d has bound to %s.\n", pb->GetId(),
  3269.           pm ? pm->GetName() : L"<unknown>");
  3270. }
  3271.  
  3272. void DebuggerShell::OnUnBindBreakpoint(DebuggerBreakpoint *pb, DebuggerModule *pm)
  3273. {
  3274.     Write(L"Breakpoint #%d has unbound from %s.\n", pb->GetId(),
  3275.           pm ? pm->GetName() : L"<unknown>");
  3276. }
  3277.  
  3278. bool DebuggerShell::ReadLine(WCHAR *buffer, int maxCount)
  3279. {
  3280.     if (fgetws(buffer, maxCount, m_in))
  3281.     {
  3282.         // Get rid of the newline character
  3283.         WCHAR *ptr = wcschr(buffer, L'\n');
  3284.         _ASSERTE(ptr && "Line was too long.  Up Debugger Shell's BUFFER_SIZE.");
  3285.         *ptr = L'\0';
  3286.  
  3287.         if (m_in != stdin)
  3288.             Write(L"%s\n", buffer);
  3289.         
  3290.         return (true);
  3291.     }
  3292.     else
  3293.     {
  3294.         *buffer = L'\0';
  3295.  
  3296.         if (m_in != stdin)
  3297.             Write(L"\n");
  3298.         
  3299.         return (!feof(m_in));
  3300.     }
  3301. }
  3302.  
  3303. void DebuggerShell::Write(const WCHAR *buffer, ...)
  3304. {
  3305.     va_list     args;
  3306.  
  3307.     va_start(args, buffer);
  3308.  
  3309.     vfwprintf(m_out, buffer, args); 
  3310.     va_end(args);
  3311. }
  3312.  
  3313. void DebuggerShell::Error(const WCHAR *buffer, ...)
  3314. {
  3315.     va_list     args;
  3316.  
  3317.     va_start(args, buffer);
  3318.  
  3319.     vfwprintf(m_out, buffer, args); 
  3320.     va_end(args);
  3321. }
  3322.  
  3323. //
  3324. // Print a little whitespace on the current line for indenting.
  3325. //
  3326.  
  3327. void DebuggerShell::PrintIndent(unsigned int level)
  3328. {
  3329.     unsigned int i;
  3330.  
  3331.     for (i = 0; i < level; i++)
  3332.         Write(L"  ");
  3333. }
  3334.  
  3335. //
  3336. // Write the name of a variable out, but only if it is valid.
  3337. //
  3338. void DebuggerShell::PrintVarName(const WCHAR* name)
  3339. {
  3340.     if (name != NULL)
  3341.         Write(L"%s=", name);
  3342. }
  3343.  
  3344. //
  3345. // Get all the indicies for an array.
  3346. //
  3347. HRESULT DebuggerShell::GetArrayIndicies(WCHAR **pp,
  3348.                                         ICorDebugILFrame *context,
  3349.                                         ULONG32 rank, ULONG32 *indicies)
  3350. {
  3351.     HRESULT hr = S_OK;
  3352.     WCHAR *p = *pp;
  3353.  
  3354.     for (unsigned int i = 0; i < rank; i++)
  3355.     {
  3356.         if (*p != L'[')
  3357.         {
  3358.             Error(L"Missing open bracked on array index.\n");
  3359.             hr = E_FAIL;
  3360.             goto exit;
  3361.         }
  3362.  
  3363.         p++;
  3364.         
  3365.         // Check for close bracket
  3366.         const WCHAR *indexStart = p;
  3367.         int nestLevel = 1;
  3368.  
  3369.         while (*p)
  3370.         {
  3371.             _ASSERTE(nestLevel != 0);
  3372.  
  3373.             if (*p == L'[')
  3374.                 nestLevel++;
  3375.  
  3376.             if (*p == L']')
  3377.                 nestLevel--;
  3378.  
  3379.             if (nestLevel == 0)
  3380.                 break;
  3381.  
  3382.             p++;
  3383.         }
  3384.  
  3385.         if (nestLevel != 0)
  3386.         {
  3387.             Error(L"Missing close bracket on array index.\n");
  3388.             hr = E_FAIL;
  3389.             goto exit;
  3390.         }
  3391.  
  3392.         const WCHAR *indexEnd = p;
  3393.         p++;
  3394.  
  3395.         // Get index
  3396.         int index;
  3397.         bool indexFound = false;
  3398.  
  3399.         if (!GetIntArg(indexStart, index))
  3400.         {
  3401.             WCHAR tmpStr[256];
  3402.  
  3403.             memcpy(tmpStr, indexStart, (indexEnd - indexStart)*sizeof(WCHAR));
  3404.             tmpStr[indexEnd - indexStart] = L'\0';
  3405.  
  3406.             ICorDebugValue *iIndexValue = EvaluateExpression(tmpStr, context);
  3407.  
  3408.             if (iIndexValue != NULL)
  3409.             {
  3410.                 ICorDebugGenericValue *igeneric;
  3411.                 hr = iIndexValue->QueryInterface(IID_ICorDebugGenericValue,
  3412.                                                  (void **) &igeneric);
  3413.  
  3414.                 if (SUCCEEDED(hr))
  3415.                 {
  3416.                     CorElementType indexType;
  3417.                     hr = igeneric->GetType(&indexType);
  3418.  
  3419.                     if (SUCCEEDED(hr))
  3420.                     {
  3421.                         if ((indexType == ELEMENT_TYPE_I1)  ||
  3422.                             (indexType == ELEMENT_TYPE_U1)  ||
  3423.                             (indexType == ELEMENT_TYPE_I2)  ||
  3424.                             (indexType == ELEMENT_TYPE_U2)  ||
  3425.                             (indexType == ELEMENT_TYPE_I4)  ||
  3426.                             (indexType == ELEMENT_TYPE_U4))
  3427.                         {
  3428.                             hr = igeneric->GetValue(&index);
  3429.  
  3430.                             if (SUCCEEDED(hr))
  3431.                                 indexFound = true;
  3432.                             else
  3433.                                 ReportError(hr);
  3434.                         }
  3435.                     }
  3436.                     else
  3437.                         ReportError(hr);
  3438.  
  3439.                     RELEASE(igeneric);
  3440.                 }
  3441.                 else
  3442.                     ReportError(hr);
  3443.  
  3444.                 RELEASE(iIndexValue);
  3445.             }
  3446.         }
  3447.         else
  3448.             indexFound = true;
  3449.  
  3450.         if (!indexFound)
  3451.         {
  3452.             Error(L"Invalid array index. Must use a number or "
  3453.                   L"a variable of type: I1, UI1, I2, UI2, I4, UI4.\n");
  3454.             hr = E_FAIL;
  3455.             goto exit;
  3456.         }
  3457.  
  3458.         indicies[i] = index;
  3459.     }
  3460.  
  3461. exit:    
  3462.     *pp = p;
  3463.     return hr;
  3464. }
  3465.  
  3466. bool DebuggerShell::EvaluateAndPrintGlobals(const WCHAR *exp)
  3467. {
  3468.     return this->MatchAndPrintSymbols((WCHAR *)exp, FALSE, true );
  3469. }
  3470.  
  3471. ICorDebugValue *DebuggerShell::EvaluateExpression(const WCHAR *exp,
  3472.                                                   ICorDebugILFrame *context,
  3473.                                                   bool silently)
  3474. {
  3475.     HRESULT hr;
  3476.     const WCHAR *p = exp;
  3477.  
  3478.     // Skip white space
  3479.     while (*p && iswspace(*p))
  3480.         p++;
  3481.  
  3482.     // First component of expression must be a name (variable or class static)
  3483.     const WCHAR *name = p;
  3484.  
  3485.     while (*p && !iswspace(*p) && *p != L'[' && *p != L'.')
  3486.         p++;
  3487.  
  3488.     if (p == name)
  3489.     {
  3490.         Error(L"Syntax error, name missing in %s\n", exp);
  3491.         return (NULL);
  3492.     }
  3493.  
  3494.     WCHAR *nameAlloc = new WCHAR[p - name + 1];
  3495.     wcsncpy(nameAlloc, name, p - name);
  3496.     nameAlloc[p-name] = L'\0';
  3497.  
  3498.     bool unavailable;
  3499.     ICorDebugValue *value = EvaluateName(nameAlloc, context, &unavailable);
  3500.  
  3501.     if (unavailable)
  3502.     {
  3503.         Error(L"Variable %s is in scope but unavailable.\n", nameAlloc);
  3504.         delete [] nameAlloc;
  3505.         return (NULL);
  3506.     }
  3507.  
  3508.     if (context == NULL)
  3509.         return value;
  3510.  
  3511.     DebuggerModule *m = NULL;
  3512.     mdTypeDef td = mdTypeDefNil;
  3513.     
  3514.     if (value == NULL)
  3515.     {
  3516.         ICorDebugClass *iclass;
  3517.         mdFieldDef fd;
  3518.         bool isStatic;
  3519.  
  3520.         // See if we've got a static field name here...
  3521.         hr = ResolveQualifiedFieldName(NULL, mdTypeDefNil, nameAlloc,
  3522.                                        &m, &td, &iclass, &fd, &isStatic);
  3523.  
  3524.         if (FAILED(hr))
  3525.         {
  3526.             if (!silently)
  3527.                 Error(L"%s is not an argument, local, or class static.\n",
  3528.                       nameAlloc);
  3529.             
  3530.             delete [] nameAlloc;
  3531.             return (NULL);
  3532.         }
  3533.  
  3534.         if (isStatic)
  3535.         {
  3536.             // We need an ICorDebugFrame to pass in here...
  3537.             ICorDebugFrame *pFrame;
  3538.             hr = context->QueryInterface(IID_ICorDebugFrame, (void**)&pFrame);
  3539.             _ASSERTE(SUCCEEDED(hr));
  3540.             
  3541.             // Grab the value of the static field off of the class.
  3542.             hr = iclass->GetStaticFieldValue(fd, pFrame, &value);
  3543.  
  3544.             RELEASE(pFrame);
  3545.  
  3546.             if (FAILED(hr))
  3547.             {
  3548.                 g_pShell->ReportError(hr);
  3549.  
  3550.                 RELEASE(iclass);
  3551.                 delete [] nameAlloc;
  3552.                 return (NULL);
  3553.             }
  3554.         }
  3555.         else
  3556.         {
  3557.             if (!silently)
  3558.                 Error(L"%s is not a static field.\n", nameAlloc);
  3559.             
  3560.             delete [] nameAlloc;
  3561.             return (NULL);
  3562.         }
  3563.     }
  3564.     
  3565.     delete [] nameAlloc;
  3566.  
  3567.     //
  3568.     // Now look for suffixes to the name
  3569.     //
  3570.     _ASSERTE(value != NULL);
  3571.     
  3572.     while (TRUE)
  3573.     {
  3574.         // Skip white space 
  3575.         while (*p != L'\0' && iswspace(*p))
  3576.             p++;
  3577.  
  3578.         if (*p == L'\0')
  3579.             return (value);
  3580.  
  3581.         switch (*p)
  3582.         {
  3583.         case L'.':
  3584.             {
  3585.                 p++;
  3586.  
  3587.                 // Strip off any reference values.
  3588.                 hr = StripReferences(&value, false);
  3589.  
  3590.                 if (FAILED(hr) || value == NULL)
  3591.                 {
  3592.                     Error(L"Cannot get field of non-object value.\n");
  3593.  
  3594.                     if (value)
  3595.                         RELEASE(value);
  3596.  
  3597.                     return NULL;
  3598.                 }
  3599.                     
  3600.                 // If we have a boxed object then unbox the little
  3601.                 // fella...
  3602.                 ICorDebugBoxValue *boxVal;
  3603.             
  3604.                 if (SUCCEEDED(value->QueryInterface(IID_ICorDebugBoxValue,
  3605.                                                     (void **) &boxVal)))
  3606.                 {
  3607.                     ICorDebugObjectValue *objVal;
  3608.                     hr = boxVal->GetObject(&objVal);
  3609.                 
  3610.                     if (FAILED(hr))
  3611.                     {
  3612.                         ReportError(hr);
  3613.                         RELEASE(boxVal);
  3614.                         RELEASE(value);
  3615.                         return NULL;
  3616.                     }
  3617.  
  3618.                     RELEASE(boxVal);
  3619.                     RELEASE(value);
  3620.  
  3621.                     // Replace the current value with the unboxed object.
  3622.                     value = objVal;
  3623.                 }
  3624.                     
  3625.                 // Now we should have an object, or we're done.
  3626.                 ICorDebugObjectValue *object;
  3627.  
  3628.                 if (FAILED(value->QueryInterface(IID_ICorDebugObjectValue,
  3629.                                                  (void **)&object)))
  3630.                 {
  3631.                     Error(L"Cannot get field of non-object value.\n");
  3632.                     RELEASE(value);
  3633.                     return NULL;
  3634.                 }
  3635.  
  3636.                 RELEASE(value);
  3637.  
  3638.                 // Get class & module
  3639.                 ICorDebugClass *iclass;
  3640.                 hr = object->GetClass(&iclass);
  3641.  
  3642.                 if (FAILED(hr))
  3643.                 {
  3644.                     g_pShell->ReportError(hr);
  3645.                     RELEASE(object);
  3646.                     return (NULL);
  3647.                 }
  3648.  
  3649.                 ICorDebugModule *imodule;
  3650.                 hr = iclass->GetModule(&imodule);
  3651.  
  3652.                 if (FAILED(hr))
  3653.                 {
  3654.                     g_pShell->ReportError(hr);
  3655.                     RELEASE(object);
  3656.                     RELEASE(iclass);
  3657.                     return (NULL);
  3658.                 }
  3659.  
  3660.                 m = DebuggerModule::FromCorDebug(imodule);
  3661.                 _ASSERTE(m != NULL);
  3662.  
  3663.                 hr = iclass->GetToken(&td);
  3664.  
  3665.                 if (FAILED(hr))
  3666.                 {
  3667.                     g_pShell->ReportError(hr);
  3668.                     RELEASE(object);
  3669.                     RELEASE(iclass);
  3670.                     return (NULL);
  3671.                 }
  3672.  
  3673.                 RELEASE(iclass);
  3674.                 RELEASE(imodule);
  3675.  
  3676.                 //
  3677.                 // Get field name
  3678.                 //
  3679.  
  3680.                 const WCHAR *field = p;
  3681.  
  3682.                 while (*p && !iswspace(*p) && *p != '[' && *p != '.')
  3683.                     p++;
  3684.  
  3685.                 if (p == field)
  3686.                 {
  3687.                     Error(L"Syntax error, field name missing in %s\n", exp);
  3688.                     return (NULL);
  3689.                 }
  3690.  
  3691.                 WCHAR *fieldAlloc = (WCHAR*) _alloca((p - field + 1) * sizeof(WCHAR));
  3692.                 wcsncpy(fieldAlloc, field, p - field);
  3693.                 fieldAlloc[p-field] = L'\0';
  3694.  
  3695.                 // Lookup field
  3696.                 mdFieldDef fd = mdFieldDefNil;
  3697.                 bool isStatic;
  3698.                 
  3699.                 hr = ResolveQualifiedFieldName(m, td, fieldAlloc,
  3700.                                                &m, &td, &iclass, &fd,
  3701.                                                &isStatic);
  3702.  
  3703.                 if (FAILED(hr))
  3704.                 {
  3705.                     Error(L"Field %s not found.\n", fieldAlloc);
  3706.  
  3707.                     RELEASE(object);
  3708.                     return (NULL);
  3709.                 }
  3710.  
  3711.                 _ASSERTE(object != NULL);
  3712.  
  3713.                 if (!isStatic)
  3714.                     object->GetFieldValue(iclass, fd, &value);
  3715.                 else
  3716.                 {
  3717.                     // We'll let the user look at static fields as if
  3718.                     // they belong to objects.
  3719.                     iclass->GetStaticFieldValue(fd, NULL, &value);
  3720.                 }
  3721.  
  3722.                 RELEASE(iclass);
  3723.                 RELEASE(object);
  3724.  
  3725.                 break;
  3726.             }
  3727.  
  3728.         case L'[':
  3729.             {
  3730.                 if (value == NULL)
  3731.                 {
  3732.                     Error(L"Cannot index a class.\n");
  3733.                     return (NULL);
  3734.                 }
  3735.  
  3736.                 // Strip off any reference values.
  3737.                 hr = StripReferences(&value, false);
  3738.  
  3739.                 if (FAILED(hr) || value == NULL)
  3740.                 {
  3741.                     Error(L"Cannot index non-array value.\n");
  3742.  
  3743.                     if (value)
  3744.                         RELEASE(value);
  3745.  
  3746.                     return NULL;
  3747.                 }
  3748.                     
  3749.                 // Get Array interface
  3750.                 ICorDebugArrayValue *array;
  3751.                 hr = value->QueryInterface(IID_ICorDebugArrayValue,
  3752.                                            (void**)&array);
  3753.  
  3754.                 RELEASE(value);
  3755.                 
  3756.                 if (FAILED(hr))
  3757.                 {
  3758.                     Error(L"Cannot index non-array value.\n");
  3759.                     return (NULL);
  3760.                 }
  3761.  
  3762.                 _ASSERTE(array != NULL);
  3763.  
  3764.                 // Get the rank
  3765.                 ULONG32 rank;
  3766.                 hr = array->GetRank(&rank);
  3767.  
  3768.                 if (FAILED(hr))
  3769.                 {
  3770.                     g_pShell->ReportError(hr);
  3771.                     RELEASE(array);
  3772.                     return NULL;
  3773.                 }
  3774.  
  3775.                 ULONG32 *indicies = (ULONG32*) _alloca(rank * sizeof(ULONG32));
  3776.  
  3777.                 hr = GetArrayIndicies((WCHAR**)&p, context, rank, indicies);
  3778.  
  3779.                 if (FAILED(hr))
  3780.                 {
  3781.                     Error(L"Error getting array indicies.\n");
  3782.                     RELEASE(array);
  3783.                     return NULL;
  3784.                 }
  3785.  
  3786.                 // Get element.
  3787.                 hr = array->GetElement(rank, indicies, &value);
  3788.  
  3789.                 RELEASE(array);
  3790.                 
  3791.                 if (FAILED(hr))
  3792.                 {
  3793.                     if (hr == E_INVALIDARG)
  3794.                         Error(L"Array index out of range.\n");
  3795.                     else
  3796.                     {
  3797.                         Error(L"Error getting array element: ");
  3798.                         ReportError(hr);
  3799.                     }
  3800.                     
  3801.                     return (NULL);
  3802.                 }
  3803.  
  3804.                 break;
  3805.             }
  3806.         default:
  3807.             Error(L"syntax error, unrecognized character \'%c\'.\n", *p);
  3808.             if (value != NULL)
  3809.                 value->Release();
  3810.             return (NULL);
  3811.         }
  3812.     }
  3813. }
  3814.  
  3815.  
  3816. HRESULT CheckForGeneratedName( bool fVar,
  3817.     ICorDebugILFrame *context, WCHAR *name,ICorDebugValue **ppiRet )
  3818. {
  3819.     WCHAR *wszVarType;
  3820.  
  3821.     if (fVar == true)
  3822.         wszVarType = L"var";
  3823.     else
  3824.         wszVarType = L"arg";
  3825.     
  3826.     if (_wcsnicmp( name, wszVarType, wcslen(wszVarType))==0)
  3827.     {
  3828.         //extract numeric & go looking for it.
  3829.         WCHAR *wszVal = (WCHAR*)(name + wcslen(wszVarType));
  3830.         WCHAR *wszStop = NULL;
  3831.         if (wcslen(wszVal)==0 )
  3832.             return E_FAIL;
  3833.         
  3834.         long number = wcstol(wszVal, &wszStop, 10);
  3835.         if (fVar == true)
  3836.             return context->GetLocalVariable(number, ppiRet);
  3837.         else
  3838.             return context->GetArgument(number, ppiRet);
  3839.     }
  3840.  
  3841.     return E_FAIL;
  3842. }
  3843.  
  3844. ICorDebugValue *DebuggerShell::EvaluateName(const WCHAR *name,
  3845.                                             ICorDebugILFrame *context,
  3846.                                             bool *unavailable)
  3847. {
  3848.     HRESULT hr;
  3849.     ICorDebugValue* piRet = NULL;
  3850.     int i;
  3851.     int argCount;
  3852.  
  3853.     *unavailable = false;
  3854.  
  3855.     // At times, it may be reasonable to have no current managed frame
  3856.     // but still want to attempt to display some pseudo-variables. So
  3857.     // if we don't have a context, skip most of the work.
  3858.     if (context == NULL)
  3859.         goto NoContext;
  3860.     
  3861.     ICorDebugCode *icode;
  3862.     hr = context->GetCode(&icode);
  3863.  
  3864.     if (FAILED(hr))
  3865.     {
  3866.         g_pShell->ReportError(hr);
  3867.         return (NULL);
  3868.     }
  3869.  
  3870.     ICorDebugFunction *ifunction;
  3871.     hr = icode->GetFunction(&ifunction);
  3872.  
  3873.     RELEASE(icode);
  3874.  
  3875.     if (FAILED(hr))
  3876.     {
  3877.         g_pShell->ReportError(hr);
  3878.         return (NULL);
  3879.     }
  3880.  
  3881.     DebuggerFunction *function;
  3882.     function = DebuggerFunction::FromCorDebug(ifunction);
  3883.     _ASSERTE(function != NULL);
  3884.  
  3885.     RELEASE(ifunction);
  3886.  
  3887.     //
  3888.     // Look for local variable.
  3889.     //
  3890.  
  3891.     ULONG32 ip;
  3892.     CorDebugMappingResult mappingResult;
  3893.     context->GetIP(&ip, &mappingResult);
  3894.  
  3895.     DebuggerVariable *localVars;
  3896.     localVars = NULL;
  3897.     unsigned int localVarCount;
  3898.  
  3899.     function->GetActiveLocalVars(ip, &localVars, &localVarCount);
  3900.     _ASSERTE((localVarCount == 0 && localVars == NULL) ||
  3901.              (localVarCount > 0 && localVars != NULL));
  3902.  
  3903.     for (i = 0; i < localVarCount; i++)
  3904.     {
  3905.         DebuggerVariable* pVar = &(localVars[i]);
  3906.         _ASSERTE(pVar && pVar->m_name);
  3907.  
  3908.         if (wcscmp(name, pVar->m_name) == 0)
  3909.         {
  3910.             hr = context->GetLocalVariable(pVar->m_varNumber, &piRet);
  3911.  
  3912.             if (FAILED(hr))
  3913.             {
  3914.                 *unavailable = true;
  3915.                 delete [] localVars;
  3916.                 return (NULL);
  3917.             }
  3918.             else
  3919.             {
  3920.                 delete [] localVars;
  3921.                 return (piRet);
  3922.             }
  3923.         }
  3924.     }
  3925.  
  3926.     delete [] localVars;
  3927.  
  3928.     //
  3929.     // Look for an argument
  3930.     //
  3931.     for (i = 0, argCount = function->GetArgumentCount(); i < argCount; i++)
  3932.     {
  3933.         DebuggerVarInfo* arg = function->GetArgumentAt(i);
  3934.  
  3935.         if (arg != NULL && arg->name != NULL)
  3936.         {
  3937.             //@TODO: Remove when DbgMeta becomes unicode
  3938.             MAKE_WIDEPTR_FROMUTF8(wArgName, arg->name);
  3939.  
  3940.             if (wcscmp(name, wArgName) == 0)
  3941.             {
  3942.                 hr = context->GetArgument(arg->varNumber, &piRet);
  3943.  
  3944.                 if (FAILED(hr))
  3945.                 {
  3946.                     *unavailable = true;
  3947.                     return (NULL);
  3948.                 }
  3949.                 else
  3950.                     return (piRet);
  3951.             }
  3952.         }
  3953.     }
  3954.  
  3955.     // at this point we haven't found anything, so assume that
  3956.     // the user simply wants to see the nth arg or var.
  3957.     // NOTE that this looks the same as what's printed out when
  3958.     // we don't have any debugging metadata for the variables
  3959.     if ( !FAILED(CheckForGeneratedName( true, context, (WCHAR*)name, &piRet)))
  3960.     {
  3961.         return piRet;
  3962.     }
  3963.     
  3964.     if ( !FAILED(CheckForGeneratedName( false, context, (WCHAR*)name, &piRet)))
  3965.     {
  3966.         return piRet;
  3967.     }
  3968.  
  3969.     // Do they want to see the result of the last func eval?
  3970.     if (!_wcsicmp(name, L"$result"))
  3971.     {
  3972.         // Get the chain this frame is in.
  3973.         ICorDebugChain *pChain;
  3974.         hr = context->GetChain(&pChain);
  3975.  
  3976.         if (SUCCEEDED(hr))
  3977.         {
  3978.             // Get the thread the chain is in.
  3979.             ICorDebugThread *pThread;
  3980.             hr = pChain->GetThread(&pThread);
  3981.  
  3982.             if (SUCCEEDED(hr))
  3983.             {
  3984.                 // Grab our managed thread object.
  3985.                 DebuggerManagedThread *dmt = GetManagedDebuggerThread(pThread);
  3986.                 _ASSERTE(dmt != NULL);
  3987.  
  3988.                 // Is there an eval to get a result from?
  3989.                 if (dmt->m_lastFuncEval)
  3990.                 {
  3991.                     hr = dmt->m_lastFuncEval->GetResult(&piRet);
  3992.  
  3993.                     if (SUCCEEDED(hr))
  3994.                         return piRet;
  3995.                 }
  3996.  
  3997.                 RELEASE(pThread);
  3998.             }
  3999.             
  4000.             RELEASE(pChain);
  4001.         }
  4002.     }
  4003.  
  4004.     // Do they want to see the thread object?
  4005.     if (!_wcsicmp(name, L"$thread"))
  4006.     {
  4007.         // Get the chain this frame is in.
  4008.         ICorDebugChain *pChain;
  4009.         hr = context->GetChain(&pChain);
  4010.  
  4011.         if (SUCCEEDED(hr))
  4012.         {
  4013.             // Get the thread the chain is in.
  4014.             ICorDebugThread *pThread;
  4015.             hr = pChain->GetThread(&pThread);
  4016.  
  4017.             if (SUCCEEDED(hr))
  4018.             {
  4019.                 // Grab our managed thread object.
  4020.                 hr = pThread->GetObject (&piRet);
  4021.  
  4022.                 if (SUCCEEDED(hr))
  4023.                 {
  4024.                     return piRet;
  4025.                 }
  4026.  
  4027.                 RELEASE(pThread);
  4028.             }
  4029.             
  4030.             RELEASE(pChain);
  4031.         }
  4032.     }
  4033.  
  4034. NoContext:
  4035.     // Do they want to see the last exception on this thread?
  4036.     if (!_wcsicmp(name, L"$exception"))
  4037.     {
  4038.         if (m_currentThread != NULL)
  4039.         {
  4040.             hr = m_currentThread->GetCurrentException(&piRet);
  4041.  
  4042.             if (SUCCEEDED(hr))
  4043.                 return piRet;
  4044.         }
  4045.     }
  4046.     
  4047.     return (NULL);
  4048. }
  4049.  
  4050. //
  4051. // Strip all references off of the given value. This simply
  4052. // dereferences through references until it hits a non-reference
  4053. // value.
  4054. //
  4055. HRESULT DebuggerShell::StripReferences(ICorDebugValue **ppValue,
  4056.                                        bool printAsYouGo)
  4057. {
  4058.     HRESULT hr = S_OK;
  4059.     
  4060.     while (TRUE)
  4061.     {
  4062.         ICorDebugReferenceValue *reference;
  4063.         hr = (*ppValue)->QueryInterface(IID_ICorDebugReferenceValue, 
  4064.                                         (void **) &reference);
  4065.  
  4066.         if (FAILED(hr))
  4067.         {
  4068.             hr = S_OK;
  4069.             break;
  4070.         }
  4071.  
  4072.         // Check for NULL
  4073.         BOOL isNull;
  4074.         hr = reference->IsNull(&isNull);
  4075.  
  4076.         if (FAILED(hr))
  4077.         {
  4078.             RELEASE(reference);
  4079.             (*ppValue)->Release();
  4080.             *ppValue = NULL;
  4081.             break;
  4082.         }
  4083.  
  4084.         if (isNull)
  4085.         {
  4086.             if (printAsYouGo)
  4087.                 Write(L"<null>");
  4088.             
  4089.             RELEASE(reference);
  4090.             (*ppValue)->Release();
  4091.             *ppValue = NULL;
  4092.             break;
  4093.         }
  4094.  
  4095.         CORDB_ADDRESS realObjectPtr;
  4096.         hr = reference->GetValue(&realObjectPtr);
  4097.  
  4098.         if (FAILED(hr))
  4099.         {
  4100.             RELEASE(reference);
  4101.             (*ppValue)->Release();
  4102.             *ppValue = NULL;
  4103.             break;
  4104.         }
  4105.  
  4106.         // Dereference the thing...
  4107.         ICorDebugValue *newValue;
  4108.         hr = reference->Dereference(&newValue);
  4109.             
  4110.         if (hr != S_OK)
  4111.         {
  4112.             if (printAsYouGo)
  4113.                 if (hr == CORDBG_E_BAD_REFERENCE_VALUE)
  4114.                     Write(L"<invalid reference: 0x%p>", realObjectPtr);
  4115.                 else if (hr == CORDBG_E_CLASS_NOT_LOADED)
  4116.                     Write(L"(0x%p) Note: NGWS error -- referenced class "
  4117.                           L"not loaded.", realObjectPtr);
  4118.                 else if (hr == CORDBG_S_VALUE_POINTS_TO_VOID)
  4119.                     Write(L"0x%p", realObjectPtr);
  4120.  
  4121.             RELEASE(reference);;
  4122.             (*ppValue)->Release();
  4123.             *ppValue = NULL;
  4124.             break;
  4125.         }
  4126.  
  4127.         if (printAsYouGo)
  4128.             Write(L"(0x%08x) ", realObjectPtr);
  4129.         
  4130.         RELEASE(reference);
  4131.  
  4132.         (*ppValue)->Release();
  4133.         *ppValue = newValue;
  4134.     }
  4135.  
  4136.     return hr;
  4137. }
  4138.  
  4139.  
  4140. #define GET_VALUE_DATA(pData, size, icdvalue)                   \
  4141.     _ASSERTE(icdvalue);                                         \
  4142.     ICorDebugGenericValue *__gv##icdvalue;                      \
  4143.     HRESULT __hr##icdvalue = icdvalue->QueryInterface(          \
  4144.                                IID_ICorDebugGenericValue,       \
  4145.                                (void**) &__gv##icdvalue);       \
  4146.     if (FAILED(__hr##icdvalue))                                 \
  4147.     {                                                           \
  4148.         g_pShell->ReportError(__hr##icdvalue);                  \
  4149.         goto exit;                                              \
  4150.     }                                                           \
  4151.     ULONG32 size;                                               \
  4152.     __hr##icdvalue = __gv##icdvalue->GetSize(&size);            \
  4153.     if (FAILED(__hr##icdvalue))                                 \
  4154.     {                                                           \
  4155.         g_pShell->ReportError(__hr##icdvalue);                  \
  4156.         RELEASE(__gv##icdvalue);                                \
  4157.         goto exit;                                              \
  4158.     }                                                           \
  4159.     void* pData = (void*) _alloca(size);                        \
  4160.     __hr##icdvalue = __gv##icdvalue->GetValue(pData);           \
  4161.     if (FAILED(__hr##icdvalue))                                 \
  4162.     {                                                           \
  4163.         g_pShell->ReportError(__hr##icdvalue);                  \
  4164.         RELEASE(__gv##icdvalue);                                \
  4165.         goto exit;                                              \
  4166.     }                                                           \
  4167.     RELEASE(__gv##icdvalue);
  4168.  
  4169. //
  4170. // Print a variable. There are a lot of options here to handle lots of
  4171. // different kinds of variables. If subfieldName is set, then it is a
  4172. // field within an object to be printed. The indent is used to keep
  4173. // indenting proper for recursive calls, and expandObjects allows you
  4174. // to specify wether or not you want the fields of an object printed.
  4175. //
  4176. void DebuggerShell::PrintVariable(const WCHAR *name,
  4177.                                   ICorDebugValue *ivalue,
  4178.                                   unsigned int indent,
  4179.                                   BOOL expandObjects)
  4180. {
  4181.     HRESULT hr;
  4182.  
  4183.     // Print the variable's name first.
  4184.     PrintVarName(name);
  4185.  
  4186.     // Strip off any reference values before the real value
  4187.     // automatically.  Note: this will release the original
  4188.     // ICorDebugValue if it is actually dereferenced for us.
  4189.     hr = StripReferences(&ivalue, true);
  4190.  
  4191.     if (FAILED(hr) && !((hr == CORDBG_E_BAD_REFERENCE_VALUE) ||
  4192.                         (hr == CORDBG_E_CLASS_NOT_LOADED) ||
  4193.                         (hr == CORDBG_S_VALUE_POINTS_TO_VOID)))
  4194.     {
  4195.         g_pShell->ReportError(hr);
  4196.         goto exit;
  4197.     }
  4198.  
  4199.     if ((ivalue == NULL) || (hr != S_OK))
  4200.         return;
  4201.     
  4202.     // Grab the element type.
  4203.     CorElementType type;
  4204.     hr = ivalue->GetType(&type);
  4205.  
  4206.     if (FAILED(hr))
  4207.     {
  4208.         g_pShell->ReportError(hr);
  4209.         goto exit;
  4210.     }
  4211.  
  4212.     // Basic types are all printed pretty much the same. See the macro
  4213.     // GET_VALUE_DATA for some of the details.
  4214.     switch (type)
  4215.     {
  4216.     case ELEMENT_TYPE_BOOLEAN:
  4217.         {
  4218.             GET_VALUE_DATA(b, bSize, ivalue);
  4219.             _ASSERTE(bSize == sizeof(BYTE));
  4220.             Write(L"%s", (*((BYTE*)b) == FALSE) ? L"false" : L"true");
  4221.             break;
  4222.         }
  4223.  
  4224.     case ELEMENT_TYPE_CHAR:
  4225.         {
  4226.             GET_VALUE_DATA(ch, chSize, ivalue);
  4227.             _ASSERTE(chSize == sizeof(WCHAR));
  4228.             if ( m_rgfActiveModes & DSM_DISPLAY_REGISTERS_AS_HEX)
  4229.                 Write( L"0x%.2x", *((WCHAR*) ch));
  4230.             else
  4231.                 Write(L"'%c'", *((WCHAR*) ch));
  4232.             break;
  4233.         }
  4234.  
  4235.     case ELEMENT_TYPE_I1:
  4236.         {
  4237.             GET_VALUE_DATA(i1, i1Size, ivalue);
  4238.             _ASSERTE(i1Size == sizeof(BYTE));
  4239.             if ( m_rgfActiveModes & DSM_DISPLAY_REGISTERS_AS_HEX)
  4240.                 Write( L"0x%.2x", *((BYTE*) i1) );
  4241.             else
  4242.                 Write(L"'%d'", *((BYTE*) i1) );
  4243.             break;
  4244.  
  4245.         }
  4246.  
  4247.     case ELEMENT_TYPE_U1:
  4248.         {
  4249.             //@todo: this is supiciously similar to I1, above
  4250.             GET_VALUE_DATA(ui1, ui1Size, ivalue);
  4251.             _ASSERTE(ui1Size == sizeof(BYTE));
  4252.             if ( m_rgfActiveModes & DSM_DISPLAY_REGISTERS_AS_HEX)
  4253.                 Write( L"0x%.2x",  *((BYTE*) ui1));
  4254.             else
  4255.                 Write(L"'%d",  *((BYTE*) ui1));
  4256.             break;
  4257.         }
  4258.  
  4259.     case ELEMENT_TYPE_I2:
  4260.         {
  4261.             GET_VALUE_DATA(i2, i2Size, ivalue);
  4262.             _ASSERTE(i2Size == sizeof(short));
  4263.             if ( m_rgfActiveModes & DSM_DISPLAY_REGISTERS_AS_HEX)
  4264.                 Write( L"0x%.4x", *((short*) i2) );
  4265.             else
  4266.                 Write(L"%d", *((short*) i2));
  4267.             break;
  4268.         }
  4269.  
  4270.     case ELEMENT_TYPE_U2:
  4271.         {
  4272.             GET_VALUE_DATA(ui2, ui2Size, ivalue);
  4273.             _ASSERTE(ui2Size == sizeof(unsigned short));
  4274.             if ( m_rgfActiveModes & DSM_DISPLAY_REGISTERS_AS_HEX)
  4275.                 Write( L"0x%.4x", *((unsigned short*) ui2) );
  4276.             else
  4277.                 Write(L"%d", *((unsigned short*) ui2));
  4278.             break;
  4279.         }
  4280.  
  4281.     case ELEMENT_TYPE_I4:
  4282.         {
  4283.             GET_VALUE_DATA(i4, i4Size, ivalue);
  4284.             _ASSERTE(i4Size == sizeof(int));
  4285.             if ( m_rgfActiveModes & DSM_DISPLAY_REGISTERS_AS_HEX)
  4286.                 Write( L"0x%.8x", *((int*) i4) );
  4287.             else
  4288.                 Write(L"%d", *((int*) i4));
  4289.             break;
  4290.         }
  4291.  
  4292.     case ELEMENT_TYPE_U4:
  4293.         {
  4294.             GET_VALUE_DATA(ui4, ui4Size, ivalue);
  4295.             _ASSERTE(ui4Size == sizeof(unsigned int));
  4296.             if ( m_rgfActiveModes & DSM_DISPLAY_REGISTERS_AS_HEX)
  4297.                 Write( L"0x%.8x", *((unsigned int*) ui4) );
  4298.             else
  4299.                 Write(L"%d", *((unsigned int*) ui4));
  4300.             break;
  4301.         }
  4302.  
  4303.     case ELEMENT_TYPE_I8:
  4304.         {
  4305.             GET_VALUE_DATA(i8, i8Size, ivalue);
  4306.             _ASSERTE(i8Size == sizeof(__int64));
  4307.             if ( m_rgfActiveModes & DSM_DISPLAY_REGISTERS_AS_HEX)
  4308.                 Write( L"0x%I64x", *((__int64*) i8) );
  4309.             else
  4310.                 Write(L"%I64d", *((__int64*) i8));
  4311.             break;
  4312.         }
  4313.  
  4314.     case ELEMENT_TYPE_U8:
  4315.         {
  4316.             GET_VALUE_DATA(ui8, ui8Size, ivalue);
  4317.             _ASSERTE(ui8Size == sizeof(unsigned __int64));
  4318.             if ( m_rgfActiveModes & DSM_DISPLAY_REGISTERS_AS_HEX)
  4319.                 Write( L"0x%I64x", *((unsigned __int64*) ui8) );
  4320.             else            
  4321.                 Write(L"%I64d", *((unsigned __int64*) ui8) );
  4322.             break;
  4323.         }
  4324.  
  4325.     case ELEMENT_TYPE_R4:
  4326.         {
  4327.             GET_VALUE_DATA(f4, f4Size, ivalue);
  4328.             _ASSERTE(f4Size == sizeof(float));
  4329.             Write(L"%.16g", *((float*) f4));
  4330.             break;
  4331.         }
  4332.  
  4333.     case ELEMENT_TYPE_R8:
  4334.         {
  4335.             GET_VALUE_DATA(f8, f8Size, ivalue);
  4336.             _ASSERTE(f8Size == sizeof(double));
  4337.             Write(L"%.16g", *((double*) f8));
  4338.             break;
  4339.         }
  4340.  
  4341.     //
  4342.     // @todo: replace MDARRAY with ARRAY when the time comes.
  4343.     //
  4344.     case ELEMENT_TYPE_CLASS:
  4345.     case ELEMENT_TYPE_OBJECT:
  4346.     case ELEMENT_TYPE_STRING:
  4347.     case ELEMENT_TYPE_SZARRAY:
  4348.     case ELEMENT_TYPE_ARRAY:
  4349.     case ELEMENT_TYPE_GENERICARRAY:
  4350.     case ELEMENT_TYPE_VALUECLASS:
  4351.         {
  4352.             // If we have a boxed object then unbox the little fella...
  4353.             ICorDebugBoxValue *boxVal;
  4354.             
  4355.             if (SUCCEEDED(ivalue->QueryInterface(IID_ICorDebugBoxValue,
  4356.                                                  (void **) &boxVal)))
  4357.             {
  4358.                 ICorDebugObjectValue *objVal;
  4359.                 hr = boxVal->GetObject(&objVal);
  4360.                 
  4361.                 if (FAILED(hr))
  4362.                 {
  4363.                     ReportError(hr);
  4364.                     RELEASE(boxVal);
  4365.                     break;
  4366.                 }
  4367.  
  4368.                 RELEASE(boxVal);
  4369.                 RELEASE(ivalue);
  4370.  
  4371.                 // Replace the current value with the unboxed object.
  4372.                 ivalue = objVal;
  4373.  
  4374.                 Write(L"(boxed) ");
  4375.             }
  4376.  
  4377.             // Is this object a string object?
  4378.             ICorDebugStringValue *istring;
  4379.             hr = ivalue->QueryInterface(IID_ICorDebugStringValue, 
  4380.                                         (void**) &istring);
  4381.  
  4382.             // If it is a string, print it out.
  4383.             if (SUCCEEDED(hr))
  4384.             {
  4385.                 PrintStringVar(istring, name, indent, expandObjects);
  4386.                 break;
  4387.             }
  4388.  
  4389.             // Might be an array...
  4390.             ICorDebugArrayValue *iarray;
  4391.             hr = ivalue->QueryInterface(IID_ICorDebugArrayValue, 
  4392.                                         (void **) &iarray);
  4393.  
  4394.             if (SUCCEEDED(hr))
  4395.             {
  4396.                 PrintArrayVar(iarray, name, indent, expandObjects);
  4397.                 break;
  4398.             }
  4399.             
  4400.             // It had better be an object by this point...
  4401.             ICorDebugObjectValue *iobject;
  4402.             hr = ivalue->QueryInterface(IID_ICorDebugObjectValue, 
  4403.                                         (void **) &iobject);
  4404.  
  4405.             if (SUCCEEDED(hr))
  4406.             {
  4407.                 PrintObjectVar(iobject, name, indent, expandObjects);
  4408.                 break;
  4409.             }
  4410.  
  4411.             // Looks like we've got a bad object here...
  4412.             ReportError(hr);
  4413.             break;
  4414.         }
  4415.  
  4416.     case ELEMENT_TYPE_BYREF: // should never have a BYREF here.
  4417.     case ELEMENT_TYPE_PTR: // should never have a PTR here.
  4418.     case ELEMENT_TYPE_TYPEDBYREF: // should never have a REFANY here.
  4419.     default:
  4420.         Write(L"[unknown variable type 0x%x]", type);
  4421.     }
  4422.  
  4423. exit:    
  4424.     RELEASE(ivalue);
  4425. }
  4426.  
  4427. void DebuggerShell::PrintArrayVar(ICorDebugArrayValue *iarray,
  4428.                                   const WCHAR* name,
  4429.                                   unsigned int indent,
  4430.                                   BOOL expandObjects)
  4431. {
  4432.     HRESULT hr;
  4433.     ULONG32 *dims;
  4434.     ULONG32 *bases = NULL;
  4435.     unsigned int i;
  4436.     
  4437.     // Get the rank
  4438.     ULONG32 rank;
  4439.     hr = iarray->GetRank(&rank);
  4440.  
  4441.     if (FAILED(hr))
  4442.     {
  4443.         g_pShell->ReportError(hr);
  4444.         goto exit;
  4445.     }
  4446.  
  4447.     // Get the element count
  4448.     ULONG32 elementCount;
  4449.     hr = iarray->GetCount(&elementCount);
  4450.  
  4451.     if (FAILED(hr))
  4452.     {
  4453.         g_pShell->ReportError(hr);
  4454.         goto exit;
  4455.     }
  4456.  
  4457.     // Get the dimensions
  4458.     dims = (ULONG32*)_alloca(rank * sizeof(ULONG32));
  4459.     hr = iarray->GetDimensions(rank, dims);
  4460.     
  4461.     if (FAILED(hr))
  4462.     {
  4463.         g_pShell->ReportError(hr);
  4464.         goto exit;
  4465.     }
  4466.  
  4467.     Write(L"array with dims=");
  4468.  
  4469.     for (i = 0; i < rank; i++)
  4470.         Write(L"[%d]", dims[i]);
  4471.     
  4472.     // Does it have base indicies?
  4473.     BOOL hasBaseIndicies;
  4474.     hr = iarray->HasBaseIndicies(&hasBaseIndicies);
  4475.     
  4476.     if (FAILED(hr))
  4477.     {
  4478.         g_pShell->ReportError(hr);
  4479.         goto exit;
  4480.     }
  4481.  
  4482.     if (hasBaseIndicies)
  4483.     {
  4484.         bases = (ULONG32*)_alloca(rank * sizeof(ULONG32));
  4485.         hr = iarray->GetBaseIndicies(rank, bases);
  4486.         
  4487.         if (FAILED(hr))
  4488.         {
  4489.             g_pShell->ReportError(hr);
  4490.             goto exit;
  4491.         }
  4492.  
  4493.         Write(L", bases=");
  4494.  
  4495.         for (i = 0; i < rank; i++)
  4496.             Write(L"[%d]", bases[i]);
  4497.     }
  4498.     
  4499.     // Get the element type of the array
  4500.     CorElementType arrayType;
  4501.     hr = iarray->GetElementType(&arrayType);
  4502.  
  4503.     if (FAILED(hr))
  4504.     {
  4505.         g_pShell->ReportError(hr);
  4506.         goto exit;
  4507.     }
  4508.  
  4509.     // If desired, print out the contents of the array, if not void.
  4510.     if (arrayType != ELEMENT_TYPE_VOID && expandObjects && rank == 1)
  4511.     {
  4512.         // Get and print each element of the array
  4513.         for (SIZE_T i = 0; i < elementCount; i++)
  4514.         {
  4515.             Write(L"\n");
  4516.             PrintIndent(indent + 1);
  4517.  
  4518.             if (bases != NULL)
  4519.                 Write(L"%s[%d] = ", name, i + bases[0]);
  4520.             else
  4521.                 Write(L"%s[%d] = ", name, i);
  4522.  
  4523.             ICorDebugValue *ielement;
  4524.             hr = iarray->GetElementAtPosition(i, &ielement);
  4525.  
  4526.             if (FAILED(hr))
  4527.             {
  4528.                 g_pShell->ReportError(hr);
  4529.                 goto exit;
  4530.             }
  4531.  
  4532.             PrintVariable(NULL, ielement, indent + 1, FALSE);
  4533.         }
  4534.     }
  4535.  
  4536. exit:
  4537.     RELEASE(iarray);
  4538. }
  4539.  
  4540. void DebuggerShell::PrintStringVar(ICorDebugStringValue *istring,
  4541.                                    const WCHAR* name,
  4542.                                    unsigned int indent,
  4543.                                    BOOL expandObjects)
  4544. {
  4545.     _ASSERTE(istring != NULL);
  4546.  
  4547.     // Get the string
  4548.     ULONG32 count;
  4549.     HRESULT hr = istring->GetLength(&count);
  4550.                     
  4551.     if (FAILED(hr))
  4552.     {
  4553.         g_pShell->ReportError(hr);
  4554.         RELEASE(istring);
  4555.         return;
  4556.     }
  4557.  
  4558.     WCHAR *s = (WCHAR *) _alloca((count + 1) * sizeof(WCHAR));
  4559.  
  4560.     if (count > 0)
  4561.     {    
  4562.         hr = istring->GetString(count, &count, s);
  4563.                 
  4564.         if (FAILED(hr))
  4565.         {
  4566.             g_pShell->ReportError(hr);
  4567.             return;
  4568.         }
  4569.     }
  4570.  
  4571.     RELEASE(istring);
  4572.  
  4573.     // Null terminate it
  4574.     s[count] = '\0';
  4575.  
  4576.     // Output to the user
  4577.     Write(L"\"%s\"", s);
  4578. }
  4579.  
  4580.  
  4581. void DebuggerShell::PrintObjectVar(ICorDebugObjectValue *iobject,
  4582.                                    const WCHAR* name,
  4583.                                    unsigned int indent,
  4584.                                    BOOL expandObjects)
  4585. {
  4586.     HRESULT hr = S_OK;
  4587.     
  4588.     _ASSERTE(iobject != NULL);
  4589.  
  4590.     DebuggerModule *dm;
  4591.  
  4592.     // Snagg the object's class.
  4593.     ICorDebugClass *iclass = NULL;
  4594.     hr = iobject->GetClass(&iclass);
  4595.     
  4596.     if (FAILED(hr))
  4597.     {
  4598.         g_pShell->ReportError(hr);
  4599.         goto exit;
  4600.     }
  4601.  
  4602.     // Get the class's token
  4603.     mdTypeDef tdClass;
  4604.     _ASSERTE(iclass != NULL);
  4605.     hr = iclass->GetToken(&tdClass);
  4606.  
  4607.     if (FAILED(hr))
  4608.     {
  4609.         g_pShell->ReportError(hr);
  4610.         RELEASE(iclass);
  4611.         goto exit;
  4612.     }
  4613.  
  4614.     // Get the module from this class
  4615.     ICorDebugModule *imodule;
  4616.     iclass->GetModule(&imodule);
  4617.     RELEASE(iclass);
  4618.     iclass = NULL;
  4619.     
  4620.     if (FAILED(hr))
  4621.     {
  4622.         g_pShell->ReportError(hr);
  4623.         goto exit;
  4624.     }
  4625.  
  4626.     dm = DebuggerModule::FromCorDebug(imodule);
  4627.     _ASSERTE(dm != NULL);
  4628.     RELEASE(imodule);
  4629.  
  4630.     if (FAILED(hr))
  4631.     {
  4632.         g_pShell->ReportError(hr);
  4633.         goto exit;
  4634.     }
  4635.  
  4636.     // Get the class name
  4637.     WCHAR       className[MAX_CLASS_NAME];
  4638.     ULONG       classNameSize;
  4639.     mdToken     parentTD;
  4640.  
  4641.     hr = dm->GetMetaData()->GetTypeDefProps(tdClass,
  4642.                                             className, MAX_CLASS_NAME,
  4643.                                             &classNameSize, NULL,
  4644.                                             NULL, &parentTD);
  4645.     
  4646.     if (FAILED(hr))
  4647.     {
  4648.         g_pShell->ReportError(hr);
  4649.         goto exit;
  4650.     }
  4651.  
  4652.     Write(L"<%s>", className);
  4653.  
  4654.     // Print all the members of this object.
  4655.     if (expandObjects)
  4656.     {
  4657.         BOOL isSuperClass = FALSE;
  4658.  
  4659.         do
  4660.         {
  4661.             if (isSuperClass)
  4662.             {
  4663.                 hr = dm->GetMetaData()->GetTypeDefProps(tdClass,
  4664.                                             className, MAX_CLASS_NAME,
  4665.                                             &classNameSize, NULL,
  4666.                                             NULL, &parentTD);
  4667.  
  4668.                 if (FAILED(hr))
  4669.                     break;
  4670.             }
  4671.     
  4672.             // Snagg the ICorDebugClass we're working with now...
  4673.             hr = dm->GetICorDebugModule()->GetClassFromToken(tdClass, &iclass);
  4674.  
  4675.             if (FAILED(hr))
  4676.                 break;
  4677.             
  4678.             HCORENUM fieldEnum = NULL;
  4679.  
  4680.             while (TRUE)
  4681.             {
  4682.                 // Get the fields one at a time
  4683.                 mdFieldDef field[1];
  4684.                 ULONG numFields = 0;
  4685.  
  4686.                 hr = dm->GetMetaData()->EnumFields(&fieldEnum,
  4687.                                                    tdClass, field, 1,
  4688.                                                    &numFields);
  4689.  
  4690.                 // No fields left
  4691.                 if (SUCCEEDED(hr) && (numFields == 0))
  4692.                     break;
  4693.                 // Error
  4694.                 else if (FAILED(hr))
  4695.                     break;
  4696.  
  4697.                 // Get the field properties
  4698.                 WCHAR name[256];
  4699.                 ULONG nameLen = 0;
  4700.                 DWORD attr = 0;
  4701.                             
  4702.                 hr = dm->GetMetaData()->GetFieldProps(field[0],
  4703.                                                       NULL,
  4704.                                                       name, 256,
  4705.                                                       &nameLen,
  4706.                                                       &attr,
  4707.                                                       NULL, NULL,
  4708.                                                       NULL, NULL, NULL);
  4709.  
  4710.                 if (FAILED(hr))
  4711.                     break;
  4712.  
  4713.                 // If it's not a static field
  4714.                 if (((attr & fdStatic) == 0) ||
  4715.                     (m_rgfActiveModes & DSM_SHOW_STATICS_ON_PRINT))
  4716.                 {
  4717.                     Write(L"\n");
  4718.                     PrintIndent(indent + 1);
  4719.  
  4720.                     if (isSuperClass &&
  4721.                         (m_rgfActiveModes & DSM_SHOW_SUPERCLASS_ON_PRINT))
  4722.                     {
  4723.                         // Print superclass field qualifiers in the
  4724.                         // syntax required to print them (i.e., use ::
  4725.                         // for the seperator in the namespace.
  4726.                         WCHAR *pc = className;
  4727.  
  4728.                         while (*pc != L'\0')
  4729.                         {
  4730.                             if (*pc == L'.')
  4731.                                 Write(L"::");
  4732.                             else
  4733.                                 Write(L"%c", *pc);
  4734.  
  4735.                             pc++;
  4736.                         }
  4737.  
  4738.                         Write(L"::");
  4739.                     }
  4740.  
  4741.                     ICorDebugValue *fieldValue;
  4742.  
  4743.                     if (attr & fdStatic)
  4744.                     {
  4745.                         Write(L"<static> ");
  4746.                         
  4747.                         // We'll let the user look at static fields as if
  4748.                         // they belong to objects.
  4749.                         hr = iclass->GetStaticFieldValue(field[0], NULL,
  4750.                                                          &fieldValue);
  4751.                     }
  4752.                     else
  4753.                         hr = iobject->GetFieldValue(iclass, field[0],
  4754.                                                     &fieldValue);
  4755.  
  4756.                     if (FAILED(hr))
  4757.                     {
  4758.                         if (hr == CORDBG_E_FIELD_NOT_AVAILABLE)
  4759.                             Write(L"%s -- field not available", name);
  4760.                         else
  4761.                             Write(L"%s -- error getting field: hr=0x%08x",
  4762.                                   name, hr);
  4763.                     }
  4764.                     else
  4765.                         PrintVariable(name, fieldValue, indent + 1, FALSE);
  4766.                 }
  4767.             }
  4768.  
  4769.             RELEASE(iclass);
  4770.  
  4771.             // Release the field enumerator
  4772.             if (fieldEnum != NULL)
  4773.                 dm->GetMetaData()->CloseEnum(fieldEnum);
  4774.  
  4775.             // Check for failure from within the loop...
  4776.             if (FAILED(hr))
  4777.             {
  4778.                 ReportError(hr);
  4779.                 goto exit;
  4780.             }
  4781.  
  4782.             // Repeat with the super class.
  4783.             isSuperClass = TRUE;
  4784.             tdClass = parentTD;
  4785.  
  4786.             if ((TypeFromToken(tdClass) == mdtTypeRef) &&
  4787.                 (tdClass != mdTypeRefNil))
  4788.             {
  4789.                 hr = ResolveTypeRef(dm, tdClass, &dm, &tdClass);
  4790.  
  4791.                 if (FAILED(hr))
  4792.                 {
  4793.                     ReportError(hr);
  4794.                     goto exit;
  4795.                 }
  4796.             }
  4797.  
  4798.         } while ((tdClass != mdTypeDefNil) && (tdClass != mdTypeRefNil));
  4799.     }
  4800.  
  4801.     // If we're expanding and this is a value class, run
  4802.     // Object::ToString on it just for fun.
  4803.     if (expandObjects)
  4804.     {
  4805.         BOOL isValueClass = FALSE;
  4806.  
  4807.         hr = iobject->IsValueClass(&isValueClass);
  4808.         _ASSERTE(SUCCEEDED(hr));
  4809.  
  4810.         if (isValueClass)
  4811.         {
  4812.             Write(L"\n");
  4813.             PrintIndent(indent + 1);
  4814.             
  4815.             IUnknown *pObject = NULL;
  4816.             
  4817.             hr = iobject->GetManagedCopy(&pObject);
  4818.  
  4819.             if (SUCCEEDED(hr))
  4820.             {
  4821.                 _Object *pIObject = NULL;
  4822.                 
  4823.                 hr = pObject->QueryInterface(IID_Object,
  4824.                                              (void**)&pIObject);
  4825.  
  4826.                 if (SUCCEEDED(hr))
  4827.                 {
  4828.                     BSTR bstr;
  4829.  
  4830.                     hr = pIObject->get_ToString(&bstr);
  4831.  
  4832.                     if (SUCCEEDED(hr))
  4833.                         Write(L"Object::ToString(%s) = %s", name, bstr);
  4834.                     else
  4835.                         Write(L"Object::ToString failed: 0x%08x", hr);
  4836.  
  4837.                     pIObject->Release();
  4838.                 }
  4839.                 else
  4840.                     Write(L"Failed to QI for _Object: 0x%08x", hr);
  4841.  
  4842.                 pObject->Release();
  4843.             }
  4844.             else if (hr == CORDBG_E_OBJECT_IS_NOT_COPYABLE_VALUE_CLASS)
  4845.                 Write(L"Cannot display Object::ToString.");
  4846.             else
  4847.                 Write(L"Failed to get managed copy of value class: 0x%08x",
  4848.                       hr);
  4849.         }
  4850.     }
  4851.  
  4852. exit:
  4853.     RELEASE(iobject);
  4854. }
  4855.  
  4856. //
  4857. // Given a class name, find the DebuggerModule that it is in and its
  4858. // mdTypeDef token.
  4859. //
  4860. HRESULT DebuggerShell::ResolveClassName(WCHAR *className,
  4861.                                         DebuggerModule **pDM,
  4862.                                         mdTypeDef *pTD)
  4863. {
  4864.     HRESULT hr = S_OK;
  4865.  
  4866.     // Find the class, by name and namespace, in any module we've loaded.
  4867.     HASHFIND find;
  4868.     DebuggerModule *m;
  4869.     
  4870.     for (m = (DebuggerModule*) g_pShell->m_modules.FindFirst(&find);
  4871.          m != NULL;
  4872.          m = (DebuggerModule*) g_pShell->m_modules.FindNext(&find))
  4873.     {
  4874.         mdTypeDef td;
  4875.         hr = FindTypeDefByName(m, className, &td);
  4876.         
  4877.         if (SUCCEEDED(hr))
  4878.         {
  4879.             *pDM = m;
  4880.             *pTD = td;
  4881.             goto exit;
  4882.         }
  4883.     }
  4884.  
  4885.     hr = E_INVALIDARG;
  4886.  
  4887. exit:
  4888.     return hr;
  4889. }
  4890.  
  4891. //
  4892. // This will find a typedef in a module, even if its nested, so long
  4893. // as the name is specified correctly.
  4894. //
  4895. HRESULT DebuggerShell::FindTypeDefByName(DebuggerModule *m,
  4896.                                          WCHAR *className,
  4897.                                          mdTypeDef *pTD)
  4898. {
  4899.     HRESULT hr = S_OK;
  4900.  
  4901.     hr = m->GetMetaData()->FindTypeDefByName(className, mdTokenNil, pTD);
  4902.  
  4903.     if (!SUCCEEDED(hr))
  4904.     {
  4905.         WCHAR *cpy = new WCHAR[wcslen(className) + 1];
  4906.         wcscpy(cpy, className);
  4907.  
  4908.         WCHAR *ns;
  4909.         WCHAR *cl;
  4910.         
  4911.         cl = wcsrchr(cpy, L'.');
  4912.  
  4913.         if ((cl == NULL) || (cl == cpy))
  4914.         {
  4915.             ns = NULL;
  4916.             cl = cpy;
  4917.         }
  4918.         else
  4919.         {
  4920.             ns = cpy;
  4921.             *cl = L'\0';
  4922.             cl++;
  4923.         }
  4924.  
  4925.         if (ns != NULL)
  4926.         {
  4927.             mdTypeDef en;
  4928.             hr = FindTypeDefByName(m, cpy, &en);
  4929.  
  4930.             if (SUCCEEDED(hr))
  4931.                 hr = m->GetMetaData()->FindTypeDefByName(cl, en, pTD);
  4932.         }
  4933.  
  4934.         delete cpy;
  4935.     }
  4936.  
  4937.     return hr;
  4938. }
  4939.  
  4940. //
  4941. // Given a DebuggerModule and a mdTypeRef token, resolve it to
  4942. // whatever DebuggerModule and mdTypeDef token the ref is refering to.
  4943. //
  4944. HRESULT DebuggerShell::ResolveTypeRef(DebuggerModule *currentDM,
  4945.                                       mdTypeRef tr,
  4946.                                       DebuggerModule **pDM,
  4947.                                       mdTypeDef *pTD)
  4948. {
  4949.     _ASSERTE(TypeFromToken(tr) == mdtTypeRef);
  4950.  
  4951.     // Get the name of the type ref.
  4952.     WCHAR className[MAX_CLASS_NAME];
  4953.     HRESULT hr = currentDM->GetMetaData()->GetTypeRefProps(tr,
  4954.                                                            NULL,
  4955.                                                            className,
  4956.                                                            MAX_CLASS_NAME,
  4957.                                                            NULL);
  4958.     if (FAILED(hr))
  4959.         return hr;
  4960.  
  4961.     return ResolveClassName(className, pDM, pTD);
  4962. }
  4963.  
  4964. //
  4965. // Split a name in the form "ns::ns::ns::class::field" into
  4966. // "ns.ns.ns.class" and "field". The output params need to be delete
  4967. // []'d by the caller.
  4968. //
  4969. HRESULT _splitColonQualifiedFieldName(WCHAR *pWholeName,
  4970.                                       WCHAR **ppClassName,
  4971.                                       WCHAR **ppFieldName)
  4972. {
  4973.     HRESULT hr = S_OK;
  4974.     
  4975.     // We're gonna be kinda gross about some of the allocations here,
  4976.     // basically over allocating for both the classname and the
  4977.     // fieldname.
  4978.     int len = wcslen(pWholeName);
  4979.  
  4980.     WCHAR *fn = NULL;
  4981.     WCHAR *cn = NULL;
  4982.  
  4983.     fn = new WCHAR[len+1];
  4984.  
  4985.     if (fn == NULL)
  4986.     {
  4987.         hr = E_OUTOFMEMORY;
  4988.         goto ErrExit;
  4989.     }
  4990.     
  4991.     cn = new WCHAR[len+1];
  4992.  
  4993.     if (cn == NULL)
  4994.     {
  4995.         hr = E_OUTOFMEMORY;
  4996.         goto ErrExit;
  4997.     }
  4998.  
  4999.     // Find the field name.
  5000.     WCHAR *lastColon;
  5001.     lastColon = wcsrchr(pWholeName, L':');
  5002.  
  5003.     if (lastColon)
  5004.     {
  5005.         // The field name is whatever is after the last colon.
  5006.         wcscpy(fn, lastColon + 1);
  5007.  
  5008.         // The class name is everything up to the last set of colons.
  5009.         WCHAR *tmp = pWholeName;
  5010.         WCHAR *newCn = cn;
  5011.  
  5012.         _ASSERTE(lastColon - 1 >= pWholeName);
  5013.         
  5014.         while (tmp < (lastColon - 1))
  5015.         {
  5016.             // We convert "::" to "."
  5017.             if (*tmp == L':')
  5018.             {
  5019.                 *newCn++ = L'.';
  5020.                 tmp++;
  5021.  
  5022.                 if (*tmp != L':')
  5023.                 {
  5024.                     // Badly formed name.
  5025.                     *ppClassName = NULL;
  5026.                     *ppFieldName = NULL;
  5027.                     hr = S_FALSE;
  5028.                     goto ErrExit;
  5029.                 }
  5030.                 else
  5031.                     tmp++;
  5032.             }
  5033.             else
  5034.                 *newCn++ = *tmp++;
  5035.         }
  5036.  
  5037.         // Null terminate the class name.
  5038.         *newCn++ = L'\0';
  5039.  
  5040.         // Make sure we didn't go over our buffer.
  5041.         _ASSERTE((newCn - cn) < len);
  5042.     }
  5043.     else
  5044.     {
  5045.         // No separator for the field name, so the whole thing is the
  5046.         // field name.
  5047.         wcscpy(fn, pWholeName);
  5048.         wcscpy(cn, L"\0");
  5049.     }
  5050.  
  5051.     // All went well, so pass out the results.
  5052.     *ppClassName = cn;
  5053.     *ppFieldName = fn;
  5054.  
  5055. ErrExit:
  5056.     if ((hr != S_OK) && fn)
  5057.         delete [] fn;
  5058.  
  5059.     if ((hr != S_OK) && cn)
  5060.         delete [] cn;
  5061.  
  5062.     return hr;
  5063. }
  5064.                                    
  5065.  
  5066. HRESULT DebuggerShell::ResolveQualifiedFieldName(DebuggerModule *currentDM,
  5067.                                                  mdTypeDef currentTD,
  5068.                                                  WCHAR *fieldName,
  5069.                                                  DebuggerModule **pDM,
  5070.                                                  mdTypeDef *pTD,
  5071.                                                  ICorDebugClass **pIClass,
  5072.                                                  mdFieldDef *pFD,
  5073.                                                  bool *pbIsStatic)
  5074. {
  5075.     HRESULT hr = S_OK;
  5076.  
  5077.     // Separate the class name from the field name.
  5078.     WCHAR *fn = NULL;
  5079.     WCHAR *cn = NULL;
  5080.  
  5081.     hr = _splitColonQualifiedFieldName(fieldName, &cn, &fn);
  5082.  
  5083.     if (hr != S_OK)
  5084.         goto exit;
  5085.  
  5086.     _ASSERTE(fn && cn);
  5087.     
  5088.     // If there is no class name, then we must have current scoping info.
  5089.     if ((cn[0] == L'\0') &&
  5090.         ((currentDM == NULL) || (currentTD == mdTypeDefNil)))
  5091.     {
  5092.         hr = E_INVALIDARG;
  5093.         goto exit;
  5094.     }
  5095.  
  5096.     // If we've got a specific class name to look for, go get it now.
  5097.     if (cn[0] != L'\0')
  5098.     {
  5099.         hr = ResolveClassName(cn, pDM, pTD);
  5100.  
  5101.         if (FAILED(hr))
  5102.             goto exit;
  5103.     }
  5104.     else
  5105.     {
  5106.         // No specific class name, so we're just using the existing
  5107.         // module and class.
  5108.         *pDM = currentDM;
  5109.         *pTD = currentTD;
  5110.     }
  5111.  
  5112. retry:
  5113.     // Now get the field off of this class.
  5114.     hr = (*pDM)->GetMetaData()->FindField(*pTD, fn, NULL, 0, pFD);
  5115.  
  5116.     if (FAILED(hr))
  5117.     {
  5118.         // Perhaps its a field on a super class?
  5119.         mdToken parentTD;
  5120.         hr = (*pDM)->GetMetaData()->GetTypeDefProps(*pTD,
  5121.                                                     NULL, 0, NULL,
  5122.                                                     NULL, NULL,
  5123.                                                     &parentTD);
  5124.  
  5125.         if (SUCCEEDED(hr))
  5126.         {
  5127.             if ((TypeFromToken(parentTD) == mdtTypeRef) &&
  5128.                 (parentTD != mdTypeRefNil))
  5129.             {
  5130.                 hr = ResolveTypeRef(*pDM, parentTD, pDM, pTD);
  5131.  
  5132.                 if (SUCCEEDED(hr))
  5133.                     goto retry;
  5134.             }
  5135.             else if ((TypeFromToken(parentTD) == mdtTypeDef) &&
  5136.                      (parentTD != mdTypeDefNil))
  5137.             {
  5138.                 *pTD = parentTD;
  5139.                 goto retry;
  5140.             }
  5141.         }
  5142.  
  5143.         hr = E_FAIL;
  5144.         goto exit;
  5145.     }
  5146.  
  5147.     // Finally, figure out if its static or not.
  5148.     DWORD attr;
  5149.     hr = (*pDM)->GetMetaData()->GetFieldProps(*pFD, NULL, NULL, 0, NULL, &attr,
  5150.                                               NULL, NULL, NULL, NULL, NULL);
  5151.  
  5152.     if (FAILED(hr))
  5153.         return hr;
  5154.  
  5155.     if (attr & fdStatic)
  5156.         *pbIsStatic = true;
  5157.     else
  5158.         *pbIsStatic = false;
  5159.     
  5160.     // Get the ICorDebugClass to go with the class we're working with.
  5161.     hr = (*pDM)->GetICorDebugModule()->GetClassFromToken(*pTD, pIClass);
  5162.  
  5163. exit:
  5164.     if (fn)
  5165.         delete [] fn;
  5166.  
  5167.     if (cn)
  5168.         delete [] cn;
  5169.  
  5170.     return hr;
  5171. }
  5172.  
  5173.  
  5174. HRESULT DebuggerShell::ResolveFullyQualifiedMethodName(
  5175.                                                WCHAR *methodName,
  5176.                                                ICorDebugFunction **ppFunc)
  5177. {
  5178.     HRESULT hr = S_OK;
  5179.     *ppFunc = NULL;
  5180.     
  5181.     // Split apart the name into namespace, class name, and method
  5182.     // name if necessary.
  5183.     WCHAR *className = NULL;
  5184.     WCHAR *methName = NULL;
  5185.  
  5186.     // Does it have a classname?
  5187.     WCHAR *classEnd = wcschr(methodName, L':');
  5188.  
  5189.     if ((classEnd != NULL) && (classEnd[1] == L':'))
  5190.     {
  5191.         // Name is class::method
  5192.         methName = classEnd + 2;
  5193.         *classEnd = L'\0';
  5194.         className = methodName;
  5195.     }
  5196.     else
  5197.         methName = methodName;
  5198.  
  5199.     // Whip over the modules looking for either our class or the
  5200.     // method (since the method could be global.)
  5201.     HASHFIND find;
  5202.     DebuggerModule *m;
  5203.     
  5204.     for (m = (DebuggerModule*) m_modules.FindFirst(&find);
  5205.          m != NULL;
  5206.          m = (DebuggerModule*) m_modules.FindNext(&find))
  5207.     {
  5208.         // Look for the type first, if we have one.
  5209.         mdTypeDef td = mdTypeDefNil;
  5210.  
  5211.         // @todo:  Make this work right for Nested classes.
  5212.         if (className != NULL)
  5213.             hr = FindTypeDefByName(m, className, &td);
  5214.  
  5215.         // Whether we found the type or not, look for a method within
  5216.         // the type. If we didn't find the type, then td ==
  5217.         // mdTypeDefNil and we'll search the global namespace in this
  5218.         // module.
  5219.         HCORENUM e = NULL;
  5220.         mdMethodDef md;
  5221.         ULONG count;
  5222.  
  5223.         // We only want the first match.
  5224.         hr = m->GetMetaData()->EnumMethodsWithName(&e, td, methName,
  5225.                                                    &md, 1, &count);
  5226.  
  5227.         if (SUCCEEDED(hr) && (count == 1))
  5228.         {
  5229.             DebuggerFunction *func = m->ResolveFunction(md, NULL);
  5230.  
  5231.             if (func != NULL)
  5232.             {
  5233.                 *ppFunc = func->m_ifunction;
  5234.                 (*ppFunc)->AddRef();
  5235.                 break;
  5236.             }
  5237.         }
  5238.     }
  5239.  
  5240.     if (m == NULL)
  5241.         hr = E_INVALIDARG;
  5242.     
  5243.     // Leave the input string like we found it.
  5244.     if (classEnd)
  5245.         *classEnd = L':';
  5246.     
  5247.     return hr;
  5248. }
  5249.  
  5250. void DebuggerShell::PrintBreakpoint(DebuggerBreakpoint *breakpoint)
  5251. {
  5252.     bool bPrinted = false;
  5253.  
  5254.     DebuggerSourceFile *pSource = NULL;
  5255.     if (breakpoint->m_managed)
  5256.     {
  5257.         if ((breakpoint->m_doc != NULL) && (breakpoint->m_pModuleList != NULL))
  5258.         {
  5259.             if ((pSource = breakpoint->m_pModuleList->m_pModule->
  5260.                     ResolveSourceFile (breakpoint->m_doc)) != NULL)
  5261.             {
  5262.                 if (pSource->GetPath() != NULL)
  5263.                 {
  5264.                     g_pShell->Write(L"#%d\t%s:%d\t", breakpoint->m_id, 
  5265.                             pSource->GetPath(), breakpoint->m_index);
  5266.  
  5267.                     bPrinted = true;
  5268.  
  5269.                 }
  5270.             }
  5271.         }
  5272.     }
  5273.  
  5274.     if (bPrinted == false)
  5275.     {
  5276.         DebuggerModule *m = NULL;
  5277.         WCHAR *pszModName = NULL;
  5278.  
  5279.         if (breakpoint->m_pModuleList != NULL)
  5280.         {
  5281.             m = breakpoint->m_pModuleList->m_pModule;
  5282.             _ASSERTE (m != NULL);
  5283.  
  5284.             if (m != NULL)
  5285.                 pszModName = m->GetName();
  5286.         }
  5287.  
  5288.         if (pszModName == NULL)
  5289.             pszModName = L"<UnknownModule>";
  5290.  
  5291.         g_pShell->Write(L"#%d\t%s!%s:%d\t", breakpoint->m_id, 
  5292.                         pszModName, breakpoint->m_name, 
  5293.                         breakpoint->m_index);
  5294.     }
  5295.  
  5296.     if (breakpoint->m_threadID != NULL_THREAD_ID)
  5297.         g_pShell->Write(L"thread 0x%x ", breakpoint->m_threadID);
  5298.  
  5299.     if (!breakpoint->m_active)
  5300.         g_pShell->Write(L"[disabled]");
  5301.  
  5302.     if (breakpoint->m_managed)
  5303.     {
  5304.         if (breakpoint->m_pModuleList == NULL)
  5305.             g_pShell->Write(L"[unbound] ");
  5306.         else
  5307.         {
  5308.             DebuggerCodeBreakpoint *bp = breakpoint->m_pModuleList->m_pModule->m_breakpoints;
  5309.  
  5310.             while (bp != NULL)
  5311.             {
  5312.                 if (bp->m_id == breakpoint->m_id)
  5313.                 {
  5314.                     bp->Print();
  5315.                     break;
  5316.                 }
  5317.                 bp = bp->m_next;
  5318.             }
  5319.         }
  5320.     }
  5321.     else
  5322.     {
  5323.         if (breakpoint->m_process == NULL)
  5324.             g_pShell->Write(L"[unbound] ");
  5325.     }
  5326.  
  5327.     g_pShell->Write(L"\n");
  5328.     if (bPrinted == true)
  5329.     {
  5330.         // Also, check if the number of lines in the source 
  5331.         // file are >= line number we want to display
  5332.         if (pSource->TotalLines() < breakpoint->m_index)
  5333.         {
  5334.             // Warn user
  5335.             g_pShell->Write(L"WARNING: Cannot display source line %d.", breakpoint->m_index);
  5336.             g_pShell->Write(L" Currently associated source file %s has only %d lines.\n",
  5337.                             pSource->GetPath(), pSource->TotalLines());
  5338.  
  5339.         }
  5340.     }
  5341. }
  5342.  
  5343. void DebuggerShell::PrintThreadPrefix(ICorDebugThread *pThread, bool forcePrint)
  5344. {
  5345.     DWORD               threadID;
  5346.  
  5347.     if (pThread)
  5348.     {
  5349.         HRESULT hr = pThread->GetID(&threadID);
  5350.  
  5351.         if (FAILED(hr))
  5352.         {
  5353.             g_pShell->ReportError(hr);
  5354.             return;
  5355.         }
  5356.  
  5357.         if (threadID != m_lastThread || forcePrint)
  5358.         {
  5359.             Write(L"[thread 0x%x] ", threadID);
  5360.             m_lastThread = threadID;
  5361.         }
  5362.     }
  5363.     else
  5364.     {
  5365.         Write(L"[No Managed Thread] ");
  5366.     }
  5367. }
  5368.  
  5369. HRESULT DebuggerShell::StepStart(ICorDebugThread *pThread,
  5370.                                  ICorDebugStepper *pStepper)
  5371. {
  5372.     DWORD dwThreadId = 0;
  5373.  
  5374.     if( pThread != NULL )
  5375.     {
  5376.         //figure out which thread to stick the stepper to in case
  5377.         //we don't complete the step (ie, the program exits first)
  5378.         HRESULT hr = pThread->GetID( &dwThreadId);
  5379.         _ASSERTE( !FAILED( hr ) );
  5380.  
  5381.         DebuggerManagedThread  *dmt = (DebuggerManagedThread  *)
  5382.             m_managedThreads.GetBase( dwThreadId );
  5383.  
  5384.         //add this to the list of steppers-in-progress
  5385.         if (pStepper)
  5386.             dmt->m_pendingSteppers->AddStepper( pStepper );
  5387.     }
  5388.     
  5389.     m_lastStepper = pStepper;
  5390.     return S_OK;
  5391. }
  5392.  
  5393. //called by DebuggerCallback::StepComplete
  5394. void DebuggerShell::StepNotify(ICorDebugThread *thread, 
  5395.                                ICorDebugStepper *pStepper)
  5396. {
  5397.     if (pStepper != m_lastStepper)
  5398.     {   // mulithreaded debugging: the step just completed is in
  5399.         // a different thread than the one that we were last in,
  5400.         // so print something so the user will know what's going on.
  5401.  
  5402.         // It looks weird to have a thread be created and then immediately 
  5403.         // complete a step, so we first check to make sure that the thread
  5404.         // hasn't just been created.
  5405.         DWORD dwThreadId;
  5406.         HRESULT hr = thread->GetID( &dwThreadId);
  5407.         
  5408.         _ASSERTE( !FAILED( hr ) );
  5409.  
  5410.         DebuggerManagedThread  *dmt = (DebuggerManagedThread  *)
  5411.             m_managedThreads.GetBase( dwThreadId );
  5412.  
  5413.         if (!dmt->fSuperfluousFirstStepCompleteMessageSuppressed)
  5414.         {
  5415.            dmt->fSuperfluousFirstStepCompleteMessageSuppressed = true;
  5416.         }
  5417.         else
  5418.         {
  5419.             PrintThreadPrefix(thread);
  5420.             Write(L" step complete\n");
  5421.         }
  5422.     }
  5423.  
  5424.     m_lastStepper = NULL;
  5425.  
  5426.     //we've completed the step, so elim. the pending step field
  5427.     if (pStepper)
  5428.     {
  5429.         DebuggerManagedThread *dmt = GetManagedDebuggerThread( thread );
  5430.         _ASSERTE( dmt != NULL );
  5431.         _ASSERTE( dmt->m_pendingSteppers->IsStepperPresent(pStepper) );
  5432.         dmt->m_pendingSteppers->RemoveStepper(pStepper);
  5433.     }
  5434. }
  5435.  
  5436. //
  5437. // Print the current source line. The parameter around specifies how many
  5438. // lines around the current line you want printed, too. If around is 0,
  5439. // only the current line is printed.
  5440. //
  5441. BOOL DebuggerShell::PrintCurrentSourceLine(unsigned int around)
  5442. {
  5443.     HRESULT hr;
  5444.     BOOL ret = FALSE;
  5445.  
  5446.     //
  5447.     // Don't do anything if there isn't a current thread.
  5448.     //
  5449.     if ((m_currentThread == NULL) || (m_currentFrame == NULL))
  5450.         return (ret);
  5451.  
  5452.     ICorDebugCode *icode;
  5453.     hr = m_currentFrame->GetCode(&icode);
  5454.  
  5455.     if (FAILED(hr))
  5456.     {
  5457.         g_pShell->ReportError(hr);
  5458.         return (FALSE);
  5459.     }
  5460.  
  5461.     ICorDebugFunction *ifunction;
  5462.     icode->GetFunction(&ifunction);
  5463.  
  5464.     RELEASE(icode);
  5465.  
  5466.     if (FAILED(hr))
  5467.     {
  5468.         g_pShell->ReportError(hr);
  5469.         return (FALSE);
  5470.     }
  5471.  
  5472.     DebuggerFunction *function = DebuggerFunction::FromCorDebug(ifunction);
  5473.     _ASSERTE(function != NULL);
  5474.  
  5475.     RELEASE(ifunction);
  5476.  
  5477.     ULONG32 ip;
  5478.     CorDebugMappingResult mappingResult;
  5479.     hr = m_currentFrame->GetIP(&ip, &mappingResult);
  5480.  
  5481.     if (FAILED(hr))
  5482.     {
  5483.         g_pShell->ReportError(hr);
  5484.         return (FALSE);
  5485.     }
  5486.  
  5487.     DebuggerSourceFile* sf;
  5488.     unsigned int lineNumber;
  5489.     hr = function->FindLineFromIP(ip, &sf, &lineNumber);
  5490.  
  5491.     if (hr == S_OK)
  5492.         ret = sf->LoadText(m_currentSourcesPath, false);
  5493.  
  5494.     if (ret && (sf->TotalLines() > 0))
  5495.     {
  5496.         unsigned int start, stop;
  5497.  
  5498.         if (lineNumber > around)
  5499.             start = lineNumber - around;
  5500.         else
  5501.             start = 1;
  5502.  
  5503.         if ((lineNumber + around) <= sf->TotalLines())
  5504.             stop = lineNumber + around;
  5505.         else
  5506.             stop = sf->TotalLines();
  5507.  
  5508.         while (start <= stop)
  5509.         {
  5510.             if ((start == lineNumber) && (around != 0))
  5511.                 Write(L"%03d:*%s\n", start, sf->GetLineText(start));
  5512.             else
  5513.                 Write(L"%03d: %s\n", start, sf->GetLineText(start));
  5514.  
  5515.             start++;
  5516.  
  5517.             ret = TRUE;
  5518.         }
  5519.  
  5520.         ActivateSourceView(sf, lineNumber);
  5521.     }
  5522.  
  5523.     if (!ret)
  5524.         return (PrintCurrentInstruction(around));
  5525.     else
  5526.         return (TRUE);
  5527. }
  5528.  
  5529.  
  5530. void DebuggerShell::ActivateSourceView(DebuggerSourceFile *psf, unsigned int lineNumber)
  5531. {
  5532. }
  5533.  
  5534.  
  5535.  
  5536. //
  5537. // Print the current source line. The parameter around specifies how many
  5538. // lines around the current line you want printed, too. If around is 0,
  5539. // only the current line is printed.
  5540. //
  5541. BOOL DebuggerShell::PrintCurrentInstruction(unsigned int around)
  5542. {
  5543.     HRESULT hr;
  5544.     // Don't do anything if there isn't a current thread.
  5545.     if ((m_currentThread == NULL) || (m_rawCurrentFrame == NULL))
  5546.         return (FALSE);
  5547.  
  5548.     ICorDebugCode *icode;
  5549.     hr = m_rawCurrentFrame->GetCode(&icode);
  5550.  
  5551.     if (FAILED(hr))
  5552.     {
  5553.         g_pShell->ReportError(hr);
  5554.         return (FALSE);
  5555.     }
  5556.  
  5557.     BOOL isIL;
  5558.     hr = icode->IsIL(&isIL);
  5559.  
  5560.     if (FAILED(hr))
  5561.     {
  5562.         g_pShell->ReportError(hr);
  5563.         RELEASE(icode);
  5564.         return (FALSE);
  5565.     }
  5566.  
  5567.     ICorDebugFunction *ifunction;
  5568.     hr = icode->GetFunction(&ifunction);
  5569.  
  5570.     RELEASE(icode);
  5571.  
  5572.     if (FAILED(hr))
  5573.     {
  5574.         g_pShell->ReportError(hr);
  5575.         return (FALSE);
  5576.     }
  5577.  
  5578.     DebuggerFunction *function = DebuggerFunction::FromCorDebug(ifunction);
  5579.     _ASSERTE(function != NULL);
  5580.  
  5581.     RELEASE(ifunction);
  5582.  
  5583.  
  5584.     ULONG32 ip;
  5585.     CorDebugMappingResult mappingResult;
  5586.  
  5587.     if (isIL)
  5588.     {
  5589.         hr = m_currentFrame->GetIP(&ip, &mappingResult);
  5590.  
  5591.         if (FAILED(hr))
  5592.         {
  5593.             g_pShell->ReportError(hr);
  5594.             return (FALSE);
  5595.         }
  5596.     }
  5597.     else
  5598.     {
  5599.         ICorDebugNativeFrame *inativeFrame;
  5600.         hr = m_rawCurrentFrame->QueryInterface(IID_ICorDebugNativeFrame,
  5601.                                                (void **)&inativeFrame);
  5602.  
  5603.         if (FAILED(hr))
  5604.         {
  5605.             g_pShell->ReportError(hr);
  5606.             return (FALSE);
  5607.         }
  5608.  
  5609.         hr = inativeFrame->GetIP(&ip);
  5610.  
  5611.         if (FAILED(hr))
  5612.         {
  5613.             g_pShell->ReportError(hr);
  5614.             return (FALSE);
  5615.         }
  5616.  
  5617.         RELEASE(inativeFrame);
  5618.     }
  5619.  
  5620. #ifdef _INTERNAL_DEBUG_SUPPORT_
  5621.     WCHAR buffer[1024];
  5622.  
  5623.     if (!isIL)
  5624.     {
  5625.         if (InitDisassembler() != TRUE)
  5626.         {
  5627.             Write(L"Unable to provide disassembly.\n");
  5628.             return (FALSE);
  5629.         }
  5630.     }
  5631.  
  5632.     if (FAILED(function->LoadCode(!isIL)))
  5633.     {
  5634.         Write(L"Unable to provide disassembly.\n");
  5635.         return (FALSE);
  5636.     }
  5637.  
  5638.     if (around == 0)
  5639.     {
  5640.         function->Disassemble(!isIL, ip, buffer);
  5641.         Write(buffer);
  5642.     }
  5643.     else
  5644.     {
  5645.         //
  5646.         // What a pain - we have to trace from the beginning of the method
  5647.         // to find the right instruction boundary.
  5648.         //
  5649.  
  5650.         size_t currentAddress = ip;
  5651.         size_t address = 0;
  5652.  
  5653.         size_t endAddress = isIL ? function->m_ilCodeSize : function->m_nativeCodeSize; 
  5654.  
  5655.         unsigned int instructionCount = 0;
  5656.         while (address < currentAddress)
  5657.         {
  5658.             size_t oldAddress = address;
  5659.  
  5660.             address = function->WalkInstruction(!isIL, address);
  5661.             if (address == 0xffff)
  5662.                 break;
  5663.             //I don't understand how this used to work - should never
  5664.             // get to next line
  5665.             if (address == oldAddress)
  5666.                 break;
  5667.  
  5668.             instructionCount++;
  5669.         }
  5670.  
  5671.         //
  5672.         // Now, walk forward again to get to the starting point.
  5673.         //
  5674.  
  5675.         address = 0;
  5676.  
  5677.         while (around < instructionCount)
  5678.         {
  5679.             address = function->WalkInstruction(!isIL, address);
  5680.             instructionCount--;
  5681.         }
  5682.  
  5683.         unsigned int i;
  5684.  
  5685.         for (i=0; i<instructionCount; i++)
  5686.         {
  5687.             Write(L" ");
  5688.             address = function->Disassemble(!isIL, address, buffer);
  5689.             Write(buffer);
  5690.         }
  5691.  
  5692.         Write(L"*");
  5693.         address = function->Disassemble(!isIL, address, buffer);
  5694.         Write(buffer);
  5695.  
  5696.         for (i=0; i<around && address < endAddress; i++)
  5697.         {
  5698.             Write(L" ");
  5699.             address = function->Disassemble(!isIL, address, buffer);
  5700.             Write(buffer);
  5701.         }
  5702.     }
  5703. #else
  5704.     Write(L"Debug information not found.\n");
  5705.     Write(L"Disassembly not supported.\n\n");
  5706. #endif
  5707.  
  5708.     return (TRUE);
  5709. }
  5710.  
  5711.  
  5712. //
  5713. // Open the registry key for persistent debugger settings.
  5714. // Returns FALSE if it fails.
  5715. //
  5716. BOOL DebuggerShell::OpenDebuggerRegistry(HKEY* key)
  5717. {
  5718.     DWORD disp;
  5719.     LONG result = RegCreateKeyExA(HKEY_CURRENT_USER, REG_DEBUGGER_KEY,
  5720.                                   NULL, NULL, REG_OPTION_NON_VOLATILE,
  5721.                                   KEY_ALL_ACCESS, NULL, key, &disp);
  5722.  
  5723.     if (result == ERROR_SUCCESS)
  5724.         return (TRUE);
  5725.  
  5726.     Error(L"Error %d opening registry key for source file "
  5727.           L"path.\n", result);
  5728.  
  5729.     return (FALSE);
  5730. }
  5731.  
  5732. //
  5733. // Close the registry key for debugger settings.
  5734. //
  5735. void DebuggerShell::CloseDebuggerRegistry(HKEY key)
  5736. {
  5737.     RegFlushKey(key);
  5738.     RegCloseKey(key);
  5739. }
  5740.  
  5741. //
  5742. // The current source file path is returned in currentPath. Free with
  5743. // delete currentPath;
  5744. // Returns FALSE if it fails.
  5745. //
  5746. BOOL DebuggerShell::ReadSourcesPath(HKEY key, WCHAR **currentPath)
  5747. {
  5748.     DWORD len = 0;
  5749.     DWORD type;
  5750.  
  5751.     // Get the length of the key data
  5752.     LONG result = RegQueryValueExA(key, REG_SOURCES_KEY, NULL,
  5753.                                    &type, NULL, &len);
  5754.  
  5755.     if (result == ERROR_SUCCESS)
  5756.     {
  5757.         // Get the key data
  5758.         char *currentPathA = (char *) _alloca(len * sizeof(char));
  5759.  
  5760.         result = RegQueryValueExA(key, REG_SOURCES_KEY, NULL,
  5761.                                     &type, (BYTE*) currentPathA, &len);
  5762.  
  5763.         // If successful, convert from ANSI to Unicode
  5764.         if (result == ERROR_SUCCESS)
  5765.         {
  5766.             MAKE_WIDEPTR_FROMUTF8(tmpWStr, currentPathA);
  5767.             *currentPath = new WCHAR[len];
  5768.             wcscpy(*currentPath, tmpWStr);
  5769.  
  5770.             return (TRUE);
  5771.         }
  5772.  
  5773.         // Otherwise indicate failure
  5774.         else
  5775.             return (FALSE);
  5776.     }
  5777.  
  5778.     return (FALSE);
  5779. }
  5780.  
  5781. //
  5782. // Write a new source file path to the registry. If successful, return
  5783. // TRUE.
  5784. //
  5785. BOOL DebuggerShell::WriteSourcesPath(HKEY key, WCHAR *newPath)
  5786. {
  5787.     // Convert the string to ANSI
  5788.     MAKE_ANSIPTR_FROMWIDE(newPathA, newPath);
  5789.  
  5790.     LONG result = RegSetValueExA(key, REG_SOURCES_KEY, NULL,
  5791.                                  REG_EXPAND_SZ, (const BYTE*) newPathA,
  5792.                                  strlen(newPathA) + 1);
  5793.  
  5794.     if (result == ERROR_SUCCESS)
  5795.         return (TRUE);
  5796.  
  5797.     Write(L"Error %d writing new path to registry.\n", result);
  5798.  
  5799.     return (FALSE);
  5800. }
  5801.  
  5802. BOOL DebuggerShell::AppendSourcesPath(const WCHAR *newpath)
  5803. {
  5804.     WCHAR        *szPath;
  5805.     int            ilen;
  5806.     ilen = wcslen(m_currentSourcesPath) + wcslen(newpath) + 4;
  5807.     szPath = new WCHAR[ilen];
  5808.     if (!szPath)
  5809.         return (FALSE);
  5810.  
  5811.     wcscpy(szPath, m_currentSourcesPath);
  5812.     wcscat(szPath, L";");
  5813.     wcscat(szPath, newpath);
  5814.     m_currentSourcesPath = szPath;
  5815.     return (TRUE);
  5816. }
  5817.  
  5818.  
  5819. // Called when we failed to find a source file on the default path.  You
  5820. // may prompt for path information.
  5821. HRESULT DebuggerShell::ResolveSourceFile(
  5822.     DebuggerSourceFile *pf,
  5823.     CHAR *pszPath, 
  5824.     CHAR *pszFullyQualName,
  5825.     int iMaxLen,
  5826.     bool bChangeOfName)
  5827. {
  5828.     HRESULT hr = S_FALSE;
  5829.     CHAR    *pstrFileName = NULL;
  5830.     DWORD fileNameLength;
  5831.  
  5832.     MAKE_ANSIPTR_FROMWIDE(nameA, pf->m_name);
  5833.     _ASSERTE(pszPath != NULL && nameA != NULL);
  5834.  
  5835.     
  5836.     // First off, check the SourceFile cache to see if there's an
  5837.     // entry matching the module and document
  5838.     ISymUnmanagedDocument *doc = NULL;
  5839.     GUID g = {0};
  5840.     if ((pf->m_module->GetSymbolReader() != NULL) &&
  5841.         SUCCEEDED(pf->m_module->GetSymbolReader()->GetDocument(pf->m_name,
  5842.                                                                 g, g, g,
  5843.                                                                 &doc)))
  5844.     {
  5845.         if (bChangeOfName == false)
  5846.         {
  5847.             m_FPCache.GetFileFromCache (pf->m_module, doc, &pstrFileName);
  5848.             if (pstrFileName != NULL)
  5849.             {
  5850.                 strcpy (pszFullyQualName, pstrFileName);
  5851.                 delete [] pstrFileName;
  5852.  
  5853.                 doc->Release();
  5854.                 
  5855.                 return S_OK;
  5856.             }
  5857.         }
  5858.         else
  5859.         {
  5860.             // We have already determined (in one of the calling func) that this file exists.
  5861.             // But we need to get the fully qualified path and also update the cache
  5862.             CHAR        rcDrive [MAX_PATH];
  5863.             CHAR        rcFile[MAX_PATH];
  5864.             CHAR        rcPath[MAX_PATH];
  5865.             CHAR        rcExt [MAX_EXT];
  5866.             _splitpath(pszPath, rcDrive, rcPath, rcFile, rcExt);
  5867.  
  5868.             strcat (rcDrive, rcPath); 
  5869.             strcat (rcFile, rcExt); 
  5870.  
  5871.             fileNameLength = SearchPathA(rcDrive, 
  5872.                                             rcFile, 
  5873.                                             NULL,
  5874.                                             iMaxLen,
  5875.                                             pszFullyQualName,
  5876.                                             NULL);
  5877.  
  5878.             if ((fileNameLength > 0) && (fileNameLength < iMaxLen))
  5879.             {
  5880.                 m_FPCache.UpdateFileCache (pf->m_module, doc,
  5881.                                            pszFullyQualName);
  5882.                 doc->Release();
  5883.  
  5884.                 return S_OK;
  5885.             }
  5886.         }
  5887.     }
  5888.  
  5889.     // Now, try to locate the file as is:
  5890.     fileNameLength = SearchPathA(NULL, nameA, NULL, iMaxLen,
  5891.                                        pszFullyQualName, NULL);
  5892.  
  5893.     if (fileNameLength == 0)
  5894.     {
  5895.         // file name was not located. So, try all the paths
  5896.  
  5897.         // extract the filename and extension from the file name
  5898.         CHAR        rcFile[MAX_PATH];
  5899.         CHAR        rcExt [MAX_EXT];
  5900.         _splitpath(nameA, NULL, NULL, rcFile, rcExt);
  5901.  
  5902.         strcat (rcFile, rcExt); 
  5903.  
  5904.         // get the number of elements in the search path
  5905.         int iNumElems = m_FPCache.GetPathElemCount();
  5906.  
  5907.         // if could be that the search path was earlier null and 
  5908.  
  5909.         char rcFullPathArray [MAX_PATH_ELEMS][MAX_PATH]; // to hold full paths for all elems
  5910.         if (iNumElems > 0)
  5911.         {
  5912.             int iCount = 0;
  5913.  
  5914.             // Initialize the array elements 
  5915.             for (int j=0; j<iNumElems; j++)
  5916.             {
  5917.                 rcFullPathArray [j][0] = '\0';
  5918.             }
  5919.             
  5920.             int iIndex = 0;
  5921.  
  5922.             // for each element in the search path, see if the file exists
  5923.             while (iIndex < iNumElems)
  5924.             {
  5925.                 char *pszPathElem = m_FPCache.GetPathElem (iIndex);
  5926.  
  5927.                 // first, try and use the unsplit name. If that doesn't return a match,
  5928.                 // use the stripped name
  5929.  
  5930.                 fileNameLength = SearchPathA(pszPathElem, 
  5931.                                                 nameA, 
  5932.                                                 NULL,
  5933.                                                 iMaxLen,
  5934.                                                 rcFullPathArray [iCount],
  5935.                                                 NULL);
  5936.                 if (fileNameLength == 0)
  5937.                 {
  5938.                     fileNameLength = SearchPathA(pszPathElem, 
  5939.                                                     rcFile, 
  5940.                                                     NULL,
  5941.                                                     iMaxLen,
  5942.                                                     rcFullPathArray [iCount],
  5943.                                                     NULL);
  5944.                 }
  5945.  
  5946.  
  5947.                 if ((fileNameLength > 0) && (fileNameLength < iMaxLen))
  5948.                 {
  5949.                     iCount++;
  5950.                 }
  5951.                     
  5952.                 iIndex++;
  5953.             }
  5954.  
  5955.             if (iCount > 0)
  5956.             {
  5957.                 // atleast one file was located
  5958.  
  5959.                 // convert all names to lowercase
  5960.                 for (int i=0; i<iCount; i++)
  5961.                 {
  5962.                     iIndex = 0;
  5963.                     while (rcFullPathArray [i][iIndex] != '\0')
  5964.                     {
  5965.                         rcFullPathArray [i][iIndex] = tolower (
  5966.                                                     rcFullPathArray[i][iIndex]);
  5967.                         iIndex++;
  5968.                     }
  5969.                 }
  5970.  
  5971.                 
  5972.                 // remove any duplicate entries
  5973.                 int iLowerBound = 1;
  5974.                 for (int iCounter1=1;    iCounter1 < iCount; iCounter1++)
  5975.                 {
  5976.                     bool fDuplicate = false;
  5977.                     for (int iCounter2=0; iCounter2 < iLowerBound;
  5978.                                                         iCounter2++)
  5979.                     {
  5980.                         if ((strcmp (rcFullPathArray [iCounter2], 
  5981.                                     rcFullPathArray [iCounter1]) == 0))
  5982.                         {
  5983.                             // found a duplicate entry. So break.
  5984.                             fDuplicate = true;
  5985.                             break;
  5986.                         }
  5987.                     }
  5988.  
  5989.                     if (fDuplicate == false)                    
  5990.                     {
  5991.                         // if we've found atleast one duplicate uptil now,
  5992.                         // then copy this entry into the entry pointed to
  5993.                         // by iLowerbound. Otherwise no need to do so (since
  5994.                         // it would be a copy to self).
  5995.                         if (iLowerBound != iCounter1)
  5996.                             strcpy (rcFullPathArray [iLowerBound],
  5997.                                     rcFullPathArray [iCounter1]);
  5998.  
  5999.                         iLowerBound++;
  6000.                     }
  6001.                 }
  6002.  
  6003.                 // new count equals the number of elements in the array (minus
  6004.                 // the duplicates)
  6005.                 iCount = iLowerBound;
  6006.  
  6007.  
  6008.                 if (iCount == 1)
  6009.                 {
  6010.                     // exactly one file was located. So this is the one!!
  6011.                     strcpy (pszFullyQualName, rcFullPathArray [0]);
  6012.  
  6013.                     // add this to the SourceFile cache
  6014.                     if (doc != NULL)
  6015.                     {
  6016.                         m_FPCache.UpdateFileCache (pf->m_module, doc,
  6017.                                                    pszFullyQualName);
  6018.                         doc->Release();
  6019.                     }
  6020.  
  6021.                     hr = S_OK;
  6022.                 }
  6023.                 else
  6024.                 {
  6025.                     // ask user to select which file he wants to open
  6026.                     while (true)
  6027.                     {
  6028.                         int iTempCount = 1;
  6029.  
  6030.                         // Print all the file names found
  6031.                         while (iTempCount <= iCount)
  6032.                         {
  6033.                             Write (L"\n%d)\t%S", iTempCount, rcFullPathArray [iTempCount - 1]);
  6034.                             iTempCount++;
  6035.                         }
  6036.  
  6037.                         bool bDone = false;
  6038.  
  6039.                         WCHAR strTemp [10+1];
  6040.                         int iResult;
  6041.                         while (true)
  6042.                         {
  6043.                             Write (L"\nPlease select one of the above options (enter the number): ");
  6044.                             if (ReadLine (strTemp, 10))
  6045.                             {
  6046.                                 WCHAR *p = strTemp;
  6047.                                 if (GetIntArg (p, iResult))
  6048.                                 {
  6049.                                         if (iResult > 0 && iResult <= iCount)
  6050.                                         {
  6051.                                         strcpy (pszFullyQualName, rcFullPathArray [iResult-1]);
  6052.                                     
  6053.                                         // add this to the SourceFile cache
  6054.                                         if (doc != NULL)
  6055.                                         {
  6056.                                             m_FPCache.UpdateFileCache (
  6057.                                                                 pf->m_module,
  6058.                                                                 doc, 
  6059.                                                                 pszFullyQualName
  6060.                                                                 );
  6061.                                             doc->Release();
  6062.                                         }
  6063.  
  6064.                                         return (S_OK);
  6065.                                     }
  6066.                                 }
  6067.                             }
  6068.  
  6069.                         }
  6070.  
  6071.                     }
  6072.                 }
  6073.             }
  6074.         }
  6075.     }
  6076.     else
  6077.     {
  6078.         // Should never exceed the maximum path length
  6079.         _ASSERTE( 0 < fileNameLength && fileNameLength <= MAX_PATH);
  6080.  
  6081.         hr = S_OK;
  6082.     }
  6083.  
  6084.     if (doc != NULL)
  6085.         doc->Release();
  6086.  
  6087.     return hr;
  6088. }
  6089.  
  6090.  
  6091. // Read the last set of debugger modes from the registry.
  6092. BOOL DebuggerShell::ReadDebuggerModes(HKEY key)
  6093. {
  6094.     DWORD len = sizeof(m_rgfActiveModes);
  6095.     DWORD type;
  6096.  
  6097.     // Get the mode word
  6098.     LONG result = RegQueryValueExA(key, REG_MODE_KEY, NULL,
  6099.                                    &type, (BYTE*) &m_rgfActiveModes, &len);
  6100.  
  6101.     if (result == ERROR_SUCCESS)
  6102.         return (TRUE);
  6103.     else
  6104.     {
  6105.         if (result != ERROR_FILE_NOT_FOUND)
  6106.             Write(L"Error %d reading debugger modes from the registry.\n",
  6107.                   result);
  6108.         
  6109.         return (FALSE);
  6110.     }
  6111. }
  6112.  
  6113. // Write the current set of debugger modes to the registry.
  6114. BOOL DebuggerShell::WriteDebuggerModes(void)
  6115. {
  6116.     HKEY key;
  6117.  
  6118.     if (OpenDebuggerRegistry(&key))
  6119.     {
  6120.         LONG result = RegSetValueExA(key, REG_MODE_KEY, NULL,
  6121.                                      REG_DWORD,
  6122.                                      (const BYTE*) &m_rgfActiveModes,
  6123.                                      sizeof(m_rgfActiveModes));
  6124.  
  6125.         CloseDebuggerRegistry(key);
  6126.         
  6127.         if (result == ERROR_SUCCESS)
  6128.             return (TRUE);
  6129.         else
  6130.         {
  6131.             Write(L"Error %d writing debugger modes to the registry.\n",
  6132.                   result);
  6133.             return (FALSE);
  6134.         }
  6135.     }
  6136.  
  6137.     return (FALSE);
  6138. }
  6139.  
  6140. ICorDebugManagedCallback *DebuggerShell::GetDebuggerCallback()
  6141. {
  6142.     return (new DebuggerCallback());
  6143. }
  6144.  
  6145.  
  6146. ICorDebugUnmanagedCallback *DebuggerShell::GetDebuggerUnmanagedCallback()
  6147. {
  6148.     return (new DebuggerUnmanagedCallback());
  6149. }
  6150.  
  6151.  
  6152. DebuggerModule *DebuggerShell::ResolveModule(ICorDebugModule *m)
  6153. {
  6154.     DebuggerModule *module = (DebuggerModule *)m_modules.GetBase((ULONG)m);
  6155.  
  6156.     return (module);
  6157. }
  6158.  
  6159. HRESULT DebuggerShell::NotifyModulesOfEnc(ICorDebugModule *pModule,
  6160.                                           IStream *pSymStream)
  6161. {
  6162.     DebuggerModule *m = DebuggerModule::FromCorDebug(pModule);
  6163.     _ASSERTE(m != NULL);
  6164.  
  6165.     if (m->m_pISymUnmanagedReader != NULL)
  6166.     {
  6167.  
  6168.         HRESULT hr = m->m_pISymUnmanagedReader->UpdateSymbolStore(NULL,
  6169.                                                                   pSymStream);
  6170.  
  6171.         if (FAILED(hr))
  6172.             Write(L"Error updating symbols for module: 0x%08x\n", hr);
  6173.     }
  6174.     
  6175.     return S_OK;
  6176. }
  6177.  
  6178. void DebuggerShell::ClearDebuggeeState(void)
  6179. {
  6180.     m_needToSkipCompilerStubs = true;
  6181. }
  6182.  
  6183. DebuggerSourceFile *DebuggerShell::LookupSourceFile(const WCHAR* name)
  6184. {
  6185.     HASHFIND find;
  6186.  
  6187.     for (DebuggerModule *module = (DebuggerModule *) m_modules.FindFirst(&find);
  6188.         module != NULL;
  6189.         module = (DebuggerModule *) m_modules.FindNext(&find))
  6190.     {
  6191.         DebuggerSourceFile *file = module->LookupSourceFile(name);
  6192.         if (file != NULL)
  6193.             return (file);
  6194.     }
  6195.  
  6196.     return (NULL);
  6197. }
  6198.  
  6199. //
  6200. // SkipCompilerStubs returns TRUE if the given thread is outside of a
  6201. // compiler compiler-generated stub. If inside a compiler stub, it
  6202. // creates a stepper on the thread and continues the process.
  6203. //
  6204. // This is really only a temporary thing in order to get VB apps past
  6205. // the compiler generated stubs and down to the real user entry
  6206. // point. In the future, we will be able to determine the proper
  6207. // entrypoint for an app and set a brekapoint there rather than going
  6208. // through all of this to step through compiler generated stubs.
  6209. //
  6210. bool DebuggerShell::SkipCompilerStubs(ICorDebugAppDomain *pAppDomain,
  6211.                                       ICorDebugThread *pThread)
  6212. {
  6213.     bool ret = true;
  6214.  
  6215.     ICorDebugChainEnum *ce;
  6216.     ICorDebugChain *ichain;
  6217.     ICorDebugFrameEnum *fe;
  6218.     ICorDebugFrame *iframe;
  6219.     ICorDebugFunction *ifunction;
  6220.     DebuggerFunction *function;
  6221.     ICorDebugStepper *pStepper;
  6222.     
  6223.     HRESULT hr = pThread->EnumerateChains(&ce);
  6224.  
  6225.     if (FAILED(hr))
  6226.         goto exit;
  6227.  
  6228.     DWORD got;
  6229.     hr = ce->Next(1, &ichain, &got);
  6230.  
  6231.     RELEASE(ce);
  6232.     
  6233.     if (FAILED(hr))
  6234.         goto exit;
  6235.  
  6236.     if (got == 1)
  6237.     {
  6238.         hr = ichain->EnumerateFrames(&fe);
  6239.  
  6240.         RELEASE(ichain);
  6241.  
  6242.         if (FAILED(hr))
  6243.             goto exit;
  6244.  
  6245.         hr = fe->Next(1, &iframe, &got);
  6246.  
  6247.         RELEASE(fe);
  6248.         
  6249.         if (FAILED(hr))
  6250.             goto exit;
  6251.  
  6252.         if (got == 1)
  6253.         {
  6254.             hr = iframe->GetFunction(&ifunction);
  6255.  
  6256.             RELEASE(iframe);
  6257.             
  6258.             if (FAILED(hr))
  6259.                 goto exit;
  6260.  
  6261.             // Get the DebuggerFunction for the function interface
  6262.             function = DebuggerFunction::FromCorDebug(ifunction);
  6263.             _ASSERTE(function);
  6264.  
  6265.             RELEASE(ifunction);
  6266.  
  6267.             WCHAR *funcName = function->GetName();
  6268.  
  6269.             // These are stub names for the only compiler we know
  6270.             // generates such stubs at this point: VB. If your
  6271.             // compiler also generates stubs that you don't want the
  6272.             // user to see, add the names in here.
  6273.             if (!wcscmp(funcName, L"_main") ||
  6274.                 !wcscmp(funcName, L"mainCRTStartup") ||
  6275.                 !wcscmp(funcName, L"_mainMSIL") ||
  6276.                 !wcscmp(funcName, L"_vbHidden_Constructor") ||
  6277.                 !wcscmp(funcName, L"_vbHidden_Destructor") ||
  6278.                 !wcscmp(funcName, L"_vbGenerated_MemberConstructor") ||
  6279.                 !wcscmp(funcName, L"_vbGenerated_StaticConstructor"))
  6280.             {
  6281.                 hr = pThread->CreateStepper(&pStepper);
  6282.  
  6283.                 if (FAILED(hr))
  6284.                     goto exit;
  6285.  
  6286.                 hr = pStepper->SetUnmappedStopMask( g_pShell->ComputeStopMask() );
  6287.                 
  6288.                 if (FAILED(hr))
  6289.                     goto exit;
  6290.  
  6291.                 hr = pStepper->SetInterceptMask( g_pShell->ComputeInterceptMask() );
  6292.                 
  6293.                 if (FAILED(hr))
  6294.                     goto exit;
  6295.                     
  6296.                 hr = pStepper->Step(TRUE);
  6297.  
  6298.                 if (FAILED(hr))
  6299.                 {
  6300.                     RELEASE(pStepper);
  6301.                     goto exit;
  6302.                 }
  6303.                 m_showSource = true;
  6304.                 StepStart(pThread, pStepper);
  6305.                 
  6306.                 ICorDebugController *dc = GetControllerInterface(pAppDomain);
  6307.                 Continue(dc, pThread);
  6308.                 
  6309.                 if (dc != NULL)
  6310.                     dc->Release();
  6311.                     
  6312.                 ret = false;
  6313.             }
  6314.         }
  6315.     }
  6316.  
  6317. exit:
  6318.     if (FAILED(hr))
  6319.         ReportError(hr);
  6320.     
  6321.     return ret;
  6322. }
  6323.  
  6324. void DebuggerShell::LoadUnmanagedSymbols(HANDLE hProcess,
  6325.                                          HANDLE hFile,
  6326.                                          DWORD imageBase)
  6327. {
  6328.     BOOL succ = SymLoadModule(hProcess, hFile, NULL, NULL, imageBase, 0);
  6329.  
  6330.     if (succ)
  6331.     {
  6332.         IMAGEHLP_MODULE mi;
  6333.         mi.SizeOfStruct = sizeof(mi);
  6334.                 
  6335.         succ = SymGetModuleInfo(hProcess, imageBase, &mi);
  6336.  
  6337.         if (succ)
  6338.         {
  6339.             char *imageName = NULL;
  6340.  
  6341.             if (mi.LoadedImageName[0] != '\0')
  6342.                 imageName = mi.LoadedImageName;
  6343.             else if (mi.ImageName[0] != '\0')
  6344.                 imageName = mi.ImageName;
  6345.             else if (mi.ModuleName[0] != '\0')
  6346.                 imageName = mi.ModuleName;
  6347.  
  6348.             if ((imageName == NULL) || (imageName[0] == '\0'))
  6349.                 imageName = "<Unknown module>";
  6350.             
  6351.             if (g_pShell->m_rgfActiveModes & DSM_SHOW_UNMANAGED_TRACE)
  6352.                 g_pShell->Write(L"Loaded symbols for %S, base=0x%08x\n",
  6353.                                 imageName, mi.BaseOfImage);
  6354.         }
  6355.         else
  6356.             g_pShell->Write(L"Error loading symbols.\n");
  6357.     }
  6358.     else
  6359.         g_pShell->Write(L"Error loading symbols.\n");
  6360. }
  6361.  
  6362. void DebuggerShell::HandleUnmanagedThreadCreate(DWORD dwThreadId,
  6363.                                                 HANDLE hThread)
  6364. {
  6365.     DebuggerUnmanagedThread *ut = new DebuggerUnmanagedThread(dwThreadId,
  6366.                                                               hThread);
  6367.     _ASSERTE(ut);
  6368.     
  6369.     HRESULT hr = g_pShell->m_unmanagedThreads.AddBase(ut);
  6370.     _ASSERTE(SUCCEEDED(hr));
  6371. }
  6372.  
  6373. void DebuggerShell::TraceUnmanagedThreadStack(HANDLE hProcess,
  6374.                                               DebuggerUnmanagedThread *ut,
  6375.                                               bool lie)
  6376. {
  6377.     HANDLE hThread = ut->GetHandle();
  6378.  
  6379.     STACKFRAME f = {0};
  6380.     BOOL succ;
  6381.     CONTEXT c;
  6382.     c.ContextFlags = CONTEXT_FULL;
  6383.  
  6384.     if ((m_currentProcess) && lie)
  6385.     {
  6386.         HRESULT hr = m_targetProcess->GetThreadContext(ut->GetId(),
  6387.                                                         sizeof(CONTEXT),
  6388.                                                         (BYTE*)&c);
  6389.  
  6390.         if (!SUCCEEDED(hr))
  6391.         {
  6392.             Write(L"Failed to get context 0x%x\n", hr);
  6393.             return;
  6394.         }
  6395.  
  6396.         Write(L"Filtered ");
  6397.     }
  6398.     else
  6399.     {
  6400.         succ = GetThreadContext(hThread, &c);
  6401.  
  6402.         if (!succ)
  6403.         {
  6404.             Write(L"Failed to get context %d\n", GetLastError());
  6405.             return;
  6406.         }
  6407.  
  6408.         Write(L"True ");
  6409.     }
  6410.  
  6411.     Write(L"stack trace for thread 0x%x:\n", ut->GetId());
  6412.  
  6413. #ifdef _X86_
  6414.     TraceUnmanagedStack(hProcess, hThread, c.Eip, c.Ebp, c.Esp, (DWORD)-1);
  6415. #else // !_X86_
  6416.     _ASSERTE(!"@TODO Alpha - TraceUnmanagedThreadStack (dShell.cpp)");
  6417. #endif // _X86_
  6418. }
  6419.  
  6420. void DebuggerShell::TraceUnmanagedStack(HANDLE hProcess, HANDLE hThread,
  6421.                                         CORDB_ADDRESS ipStart, 
  6422.                                         CORDB_ADDRESS bpStart, 
  6423.                                         CORDB_ADDRESS spStart,
  6424.                                         CORDB_ADDRESS bpEnd)
  6425. {
  6426.     STACKFRAME f = {0};
  6427.  
  6428.     f.AddrPC.Offset = ipStart;
  6429.     f.AddrPC.Mode = AddrModeFlat;
  6430.     f.AddrReturn.Mode = AddrModeFlat;
  6431.     f.AddrFrame.Offset = bpStart;
  6432.     f.AddrFrame.Mode = AddrModeFlat;
  6433.     f.AddrStack.Offset = spStart;
  6434.     f.AddrStack.Mode = AddrModeFlat;
  6435.  
  6436.     do
  6437.     {
  6438.         if (!StackWalk(IMAGE_FILE_MACHINE_I386,
  6439.                          hProcess,
  6440.                          hThread,
  6441.                          &f,
  6442.                          NULL,
  6443.                          NULL,
  6444.                          SymFunctionTableAccess,
  6445.                          SymGetModuleBase,
  6446.                          NULL))
  6447.             break;
  6448.  
  6449.         if (f.AddrPC.Offset == 0)
  6450.             continue;
  6451.  
  6452.         PrintUnmanagedStackFrame(hProcess, f.AddrPC.Offset);
  6453.         Write(L"\n");
  6454.     }
  6455.     while ((f.AddrFrame.Offset <= bpEnd) && (m_unmanagedDebuggingEnabled));
  6456. }
  6457.  
  6458. void DebuggerShell::PrintUnmanagedStackFrame(HANDLE hProcess, CORDB_ADDRESS ip)
  6459. {
  6460.     DWORD disp;
  6461.     IMAGEHLP_SYMBOL *sym = (IMAGEHLP_SYMBOL*) _alloca(sizeof(sym) +
  6462.                                                       256);
  6463.     sym->SizeOfStruct = sizeof(sym) + 256;
  6464.     sym->MaxNameLength = 256;
  6465.     
  6466.     BOOL succ;
  6467.     succ = SymGetSymFromAddr(hProcess, ip, &disp, sym);
  6468.  
  6469.     if (!succ)
  6470.         Write(L"\t0x%p:  <unknown>", (DWORD)ip, sym->Name);
  6471.     else
  6472.         Write(L"\t0x%p:  %S + %d", (DWORD)ip, sym->Name, disp);
  6473. }
  6474.  
  6475. void DebuggerShell::TraceAllUnmanagedThreadStacks(void)
  6476. {
  6477.     if (m_targetProcess == NULL)
  6478.     {
  6479.         Error(L"Process not running.\n");
  6480.         return;
  6481.     }
  6482.         
  6483.     // Snagg the handle for this process.
  6484.     HPROCESS hProcess;
  6485.     HRESULT hr = m_targetProcess->GetHandle(&hProcess);
  6486.  
  6487.     if (FAILED(hr))
  6488.     {
  6489.         ReportError(hr);
  6490.         return;
  6491.     }
  6492.  
  6493.     HASHFIND find;
  6494.     DebuggerUnmanagedThread *ut;
  6495.     
  6496.     for (ut = (DebuggerUnmanagedThread*) m_unmanagedThreads.FindFirst(&find);
  6497.          ut != NULL;
  6498.          ut = (DebuggerUnmanagedThread*) m_unmanagedThreads.FindNext(&find))
  6499.     {
  6500.         Write(L"\n\n");
  6501.         TraceUnmanagedThreadStack(hProcess, ut, false);
  6502.     }
  6503. }
  6504.  
  6505.  
  6506. int    DebuggerShell::GetUserSelection  (DebuggerModule *rgpDebugModule[],
  6507.                         WCHAR *rgpstrFileName[][MAX_FILE_MATCHES_PER_MODULE],    
  6508.                         int rgiCount[],
  6509.                         int iModuleCount,
  6510.                         int iCumulCount
  6511.                         )
  6512. {
  6513.     int iOptionCounter = 1; // User gets the breakpoint options starting from 1
  6514.     WCHAR rgwcModuleName [MAX_PATH+1];
  6515.     ULONG32 NameLength;
  6516.  
  6517.     for (int i=0; i<iModuleCount; i++)
  6518.     {
  6519.         if (rgpDebugModule [i] != NULL)
  6520.         {
  6521.             // Initialize module name to null
  6522.             rgwcModuleName [0] = L'\0';
  6523.  
  6524.             // Now get the module name
  6525.             rgpDebugModule [i]->GetICorDebugModule()->GetName(MAX_PATH, &NameLength, rgwcModuleName);
  6526.  
  6527.             for (int j=0; j < rgiCount[i]; j++)
  6528.             {
  6529.                 Write (L"%d]\t%s!%s\n",  iOptionCounter, rgwcModuleName, rgpstrFileName [i][j]);
  6530.                 iOptionCounter++;
  6531.             }
  6532.         }
  6533.     }
  6534.  
  6535.     Write (L"%d\tAll of the above\n", iOptionCounter); 
  6536.     Write (L"\nPlease select one of the above :");
  6537.  
  6538.     bool bDone = false;
  6539.  
  6540.     WCHAR strTemp [10+1];
  6541.     int iResult;
  6542.     while (true)
  6543.     {
  6544.         if (ReadLine (strTemp, 10))
  6545.         {
  6546.             WCHAR *p = strTemp;
  6547.             if (GetIntArg (p, iResult))
  6548.                 if ((iResult > 0) && (iResult <= iOptionCounter))
  6549.                     return iResult;
  6550.  
  6551.         }
  6552.  
  6553.     }
  6554.  
  6555. }
  6556.  
  6557.  
  6558. BOOL    DebuggerShell::ChangeCurrStackFile (WCHAR *fileName)
  6559. {
  6560.     // first, check to see if the file even exists. Otherwise error out.
  6561.     MAKE_ANSIPTR_FROMWIDE (fnameA, fileName);
  6562.     _ASSERTE (fnameA != NULL);
  6563.  
  6564.     FILE *stream = fopen (fnameA, "r");
  6565.     DebuggerSourceFile *pSource = NULL;
  6566.     HRESULT hr;
  6567.     BOOL ret = FALSE;
  6568.  
  6569.  
  6570.     if (stream != NULL)
  6571.     {
  6572.         fclose (stream);
  6573.  
  6574.         //
  6575.         // Don't do anything if there isn't a current thread.
  6576.         //
  6577.         if ((m_currentThread == NULL) || (m_currentFrame == NULL))
  6578.             return (ret);
  6579.  
  6580.         ICorDebugCode *icode;
  6581.         hr = m_currentFrame->GetCode(&icode);
  6582.  
  6583.         if (FAILED(hr))
  6584.         {
  6585.             g_pShell->ReportError(hr);
  6586.             return (FALSE);
  6587.         }
  6588.  
  6589.         ICorDebugFunction *ifunction;
  6590.         icode->GetFunction(&ifunction);
  6591.  
  6592.         RELEASE(icode);
  6593.  
  6594.         if (FAILED(hr))
  6595.         {
  6596.             g_pShell->ReportError(hr);
  6597.             return (FALSE);
  6598.         }
  6599.  
  6600.         DebuggerFunction *function = DebuggerFunction::FromCorDebug(ifunction);
  6601.         _ASSERTE(function != NULL);
  6602.  
  6603.         RELEASE(ifunction);
  6604.  
  6605.         ULONG32 ip;
  6606.         CorDebugMappingResult mappingResult;
  6607.         hr = m_currentFrame->GetIP(&ip, &mappingResult);
  6608.  
  6609.         if (FAILED(hr))
  6610.         {
  6611.             g_pShell->ReportError(hr);
  6612.             return (FALSE);
  6613.         }
  6614.  
  6615.         DebuggerSourceFile* sf;
  6616.         unsigned int lineNumber;
  6617.         hr = function->FindLineFromIP(ip, &sf, &lineNumber);
  6618.  
  6619.         if (hr == S_OK)
  6620.             ret = sf->ReloadText(fileName, true);    
  6621.     }
  6622.     else
  6623.     {
  6624.         g_pShell->Write(L"Could not locate/open given file.\n");
  6625.     }
  6626.  
  6627.     return ret;
  6628. }
  6629.  
  6630.  
  6631. BOOL DebuggerShell::UpdateCurrentPath (WCHAR *newPath)
  6632. {
  6633.     int iLength = wcslen (newPath);
  6634.  
  6635.     if (iLength != 0)
  6636.     {
  6637.         // Delete the previous path
  6638.         delete [] m_currentSourcesPath;
  6639.  
  6640.         // Write the new path into m_currentSourcesPath
  6641.         if ((m_currentSourcesPath = new WCHAR [iLength+1]) == NULL)
  6642.         {
  6643.             Error(L"Path not set!\n");
  6644.             m_currentSourcesPath = NULL;
  6645.             return false;
  6646.         }
  6647.  
  6648.         wcscpy (m_currentSourcesPath, newPath);
  6649.  
  6650.         // Now, store this in the DebuggerFilePathCache
  6651.         HRESULT hr = m_FPCache.InitPathArray (m_currentSourcesPath);
  6652.  
  6653.         _ASSERTE (hr == S_OK);
  6654.     }
  6655.  
  6656.     return (true);
  6657. }
  6658.  
  6659.  
  6660. // BOOL fSymbol true if we want to print symbols, false if we
  6661. //          want to print the values of global variables
  6662. bool DebuggerShell::MatchAndPrintSymbols (WCHAR *pszArg, 
  6663.                                           BOOL fSymbol, 
  6664.                                           bool fSilently)
  6665. {
  6666.     // separate the module name from the string to search for
  6667.     WCHAR szModName [MAX_PATH];
  6668.     WCHAR szSymName [MAX_SYMBOL_NAME_LENGTH];
  6669.     BOOL fAtleastOne = FALSE;
  6670.     ModuleSearchList MSL;
  6671.  
  6672.     // separate the module and searchstring
  6673.     int iIndex = 0;
  6674.     int iLength = wcslen (pszArg);
  6675.     szModName [0] = L'\0';
  6676.     szSymName [0] = L'\0';
  6677.  
  6678.     while (iIndex < iLength)
  6679.     {
  6680.         if (pszArg [iIndex] == '!')
  6681.         {
  6682.             if (iIndex > 0)
  6683.             {
  6684.                 wcsncpy (szModName, pszArg, iIndex);
  6685.                 szModName [iIndex] = L'\0';
  6686.             }
  6687.         
  6688.             wcscpy (szSymName, &pszArg [iIndex+1]);
  6689.             break;
  6690.         }
  6691.  
  6692.         iIndex++;
  6693.     }
  6694.  
  6695.     if (iIndex == iLength)
  6696.         wcscpy (szSymName, pszArg);
  6697.  
  6698.     // if no module is specified, then need to walk through all modules...
  6699.     if (wcslen (szModName) == 0)
  6700.     {
  6701.         HASHFIND find;
  6702.         DebuggerModule *m;
  6703.  
  6704.         for (m = (DebuggerModule*) g_pShell->m_modules.FindFirst(&find);
  6705.              m != NULL;
  6706.              m = (DebuggerModule*) g_pShell->m_modules.FindNext(&find))
  6707.         {
  6708.             WCHAR *pszModName = m->GetName();
  6709.             if (pszModName == NULL)
  6710.                 pszModName = L"<UnknownName>";
  6711.  
  6712.             char        rcFile[MAX_PATH];
  6713.             char        rcExt[64];
  6714.  
  6715.             MAKE_ANSIPTR_FROMWIDE(nameA, pszModName);
  6716.             _splitpath(nameA, NULL, NULL, rcFile, rcExt);
  6717.             strcat(rcFile, rcExt);
  6718.  
  6719.             // There could be multiple instances of DebuggerModule object 
  6720.             // for the same base module. Therefore, check to see if this module 
  6721.             // has already been searched
  6722.             if (!MSL.ModuleAlreadySearched (rcFile))
  6723.             {
  6724.                 // add this module to the list of modules already searched
  6725.                 MSL.AddModuleToAlreadySearchedList (rcFile);
  6726.  
  6727.                 // get the MetaData
  6728.                 IMetaDataImport *pMD = m->GetMetaData();
  6729.                 if (pMD != NULL)
  6730.                 {
  6731.                     if (fSymbol)
  6732.                     {
  6733.                         if (m->PrintMatchingSymbols (szSymName, rcFile) == TRUE)
  6734.                             fAtleastOne = TRUE;
  6735.                     }
  6736.                     else
  6737.                     {
  6738.                         if (m->PrintGlobalVariables(szSymName, rcFile, m) == TRUE)
  6739.                             fAtleastOne = TRUE;
  6740.                     }
  6741.                 }
  6742.                 else
  6743.                 {
  6744.                     if (!fSilently)
  6745.                         Write (L"**ERROR** No MetaData available for module : %S\n", rcFile);
  6746.                 }
  6747.             }
  6748.         }
  6749.     }
  6750.     else
  6751.     {
  6752.         // see if the given file name matches
  6753.         char        rcFile1[MAX_PATH];
  6754.         char        rcExt1[64];
  6755.  
  6756.         MAKE_ANSIPTR_FROMWIDE(name1A, szModName);
  6757.         _splitpath(name1A, NULL, NULL, rcFile1, rcExt1);
  6758.         strcat(rcFile1, rcExt1);
  6759.         char *pTemp = rcFile1;
  6760.         while (*pTemp != '\0')
  6761.         {    
  6762.             *pTemp = tolower (*pTemp);
  6763.             pTemp++;
  6764.         }
  6765.  
  6766.         // walk the list of modules looking for the one which 
  6767.         // matches the given module name
  6768.         HASHFIND find;
  6769.         DebuggerModule *m;
  6770.         for (m = (DebuggerModule*) g_pShell->m_modules.FindFirst(&find);
  6771.              m != NULL;
  6772.              m = (DebuggerModule*) g_pShell->m_modules.FindNext(&find))
  6773.         {
  6774.             WCHAR *pszModName = m->GetName();
  6775.             if (pszModName == NULL)
  6776.                 pszModName = L"<UnknownName>";
  6777.  
  6778.             char        rcFile[MAX_PATH];
  6779.             char        rcExt[64];
  6780.  
  6781.             MAKE_ANSIPTR_FROMWIDE(nameA, pszModName);
  6782.             _splitpath(nameA, NULL, NULL, rcFile, rcExt);
  6783.             // need to concatenate the extension only if the user had supplied it
  6784.             if (strlen (rcExt1))
  6785.                 strcat(rcFile, rcExt);
  6786.  
  6787.             // convert the name to lowercase
  6788.             pTemp = rcFile;
  6789.             while (*pTemp != '\0')
  6790.             {    
  6791.                 *pTemp = tolower (*pTemp);
  6792.                 pTemp++;
  6793.             }
  6794.             
  6795.             if (!strcmp (rcFile, rcFile1))
  6796.             {
  6797.                 // this is the one!!
  6798.  
  6799.                 // get the MetaData
  6800.                 IMetaDataImport *pMD = m->GetMetaData();
  6801.                 if (pMD != NULL)
  6802.                 {
  6803.                     if (fSymbol)
  6804.                     {
  6805.                         if (m->PrintMatchingSymbols (szSymName, rcFile) == TRUE)
  6806.                             fAtleastOne = TRUE;
  6807.                     }
  6808.                     else
  6809.                     {
  6810.                         if (m->PrintGlobalVariables(szSymName, rcFile, m) == TRUE)
  6811.                             fAtleastOne = TRUE;
  6812.                     }
  6813.                 }
  6814.                 else
  6815.                 {
  6816.                     if (!fSilently)
  6817.                         Write (L"**ERROR** No MetaData available for module : %S\n", rcFile);
  6818.                 }
  6819.                 break;
  6820.             }
  6821.         }
  6822.     }
  6823.  
  6824.     if (fAtleastOne == FALSE)
  6825.     {
  6826.         if (wcslen (szModName) == 0)
  6827.         {
  6828.             if (!fSilently)
  6829.                 Write (L"No matching symbols found in any of the loaded modules.\n");
  6830.         }
  6831.         else
  6832.         {
  6833.             if (!fSilently)
  6834.                 Write (L"No matching symbols found in module: %s .\n", szModName);
  6835.         }
  6836.         
  6837.         return false;
  6838.     }
  6839.  
  6840.     return true;
  6841. }
  6842.  
  6843. const WCHAR *DebuggerShell::UserThreadStateToString(CorDebugUserState us)
  6844. {
  6845.     WCHAR *wsz;
  6846.  
  6847.     switch (us)
  6848.     {
  6849.         case USER_STOP_REQUESTED:
  6850.             wsz = L"Stop Requested";
  6851.             break;
  6852.         case USER_SUSPEND_REQUESTED:
  6853.             wsz = L"Suspend Requested";
  6854.             break;
  6855.         case USER_BACKGROUND:
  6856.             wsz = L"Background";
  6857.             break;
  6858.         case USER_UNSTARTED:
  6859.             wsz = L"Unstarted";
  6860.             break;
  6861.         case USER_STOPPED:
  6862.             wsz = L"Stopped";
  6863.             break;
  6864.         case USER_WAIT_SLEEP_JOIN:
  6865.             wsz = L"Wait/Sleep/Join";
  6866.             break;
  6867.         case USER_SUSPENDED:
  6868.             wsz = L"Suspended";
  6869.             break;
  6870.         default:
  6871.             wsz = L"Normal";
  6872.             break;
  6873.     }
  6874.  
  6875.     return wsz;
  6876. }
  6877.  
  6878. void UndecorateName(MDUTF8CSTR name, MDUTF8STR u_name)
  6879. {
  6880.     int i, j;
  6881.     int len;
  6882.  
  6883.     len = strlen(name);
  6884.     j = 0;
  6885.     for (i = 1; i < len; i++)
  6886.     {
  6887.         if (j > 255) break;
  6888.         if (name[i] != '@') u_name[j++] = name[i];
  6889.          else break;
  6890.     }
  6891.  
  6892.     u_name[j] = '\0';
  6893. }
  6894.  
  6895. void DebuggerShell::ListAllGlobals (DebuggerModule *m)
  6896. {
  6897.     IMetaDataImport *pIMetaDI;
  6898.     HCORENUM phEnum = 0;
  6899.     mdMethodDef rTokens[100];
  6900.     int i;
  6901.     unsigned long count;
  6902.     HRESULT hr;
  6903.     MDUTF8CSTR name;
  6904.     MDUTF8STR  u_name;
  6905.     bool anythingPrinted = false;
  6906.  
  6907.     pIMetaDI = m->GetMetaData();
  6908.  
  6909.     u_name = new char[256];
  6910.  
  6911.     do 
  6912.     {
  6913.         hr = pIMetaDI->EnumMethods(&phEnum, NULL, &rTokens[0], 100, &count);
  6914.  
  6915.         if (!SUCCEEDED(hr))
  6916.         {
  6917.             ReportError(hr);
  6918.             goto ErrExit;
  6919.         }
  6920.  
  6921.         for (i = 0; i < count; i++)
  6922.         {
  6923.             hr = pIMetaDI->GetNameFromToken(rTokens[i], &name);
  6924.  
  6925.             if (name == NULL)
  6926.                 continue;
  6927.  
  6928.             Write(L"\t");
  6929.             
  6930.             if (name[0] == '?')
  6931.             {
  6932.                 UndecorateName(name, u_name);
  6933.                         
  6934.                 Write(L"%S (%S)\n", u_name, name);
  6935.             }
  6936.             else
  6937.                 Write(L"%S\n", name);
  6938.  
  6939.             anythingPrinted = true;
  6940.         }
  6941.     }
  6942.     while (count > 0); 
  6943.  
  6944. ErrExit:    
  6945.     delete u_name;
  6946.  
  6947.     if (!anythingPrinted)
  6948.         Write(L"No global functions in this module.\n");
  6949. }
  6950.  
  6951. void DebuggerShell::ListAllModules (ListType lt)
  6952. {
  6953.     HASHFIND find;
  6954.     DebuggerModule *m;
  6955.     
  6956.     for (m = (DebuggerModule*) g_pShell->m_modules.FindFirst(&find);
  6957.          m != NULL;
  6958.          m = (DebuggerModule*) g_pShell->m_modules.FindNext(&find))
  6959.     {
  6960.         _printModule(m->GetICorDebugModule(), PT_NONE);
  6961.  
  6962.         if (lt == LIST_CLASSES)
  6963.         {
  6964.             HASHFIND classfind;
  6965.             DebuggerClass *cl;
  6966.     
  6967.             for (cl = (DebuggerClass*) m->m_loadedClasses.FindFirst(&classfind);
  6968.                  cl != NULL;
  6969.                  cl = (DebuggerClass*) m->m_loadedClasses.FindNext(&classfind))
  6970.             {
  6971.                 WCHAR *pszClassName = cl->GetName();
  6972.                 WCHAR *pszNamespace = cl->GetNamespace();
  6973.  
  6974.                 if (pszClassName == NULL)
  6975.                     pszClassName = L"<UnknownClassName>";
  6976.  
  6977.                 Write (L"\t");
  6978.                 if (pszNamespace != NULL)
  6979.                     Write (L"%s.", pszNamespace);
  6980.                 Write (L"%s\n", pszClassName);
  6981.             }
  6982.         }
  6983.  
  6984.         // List all the global functions here.
  6985.         if (lt == LIST_FUNCTIONS)
  6986.         {
  6987.              ListAllGlobals(m);    
  6988.         }
  6989.     }
  6990. }
  6991.  
  6992.  
  6993.  
  6994. /* ------------------------------------------------------------------------- *
  6995.  * DebuggerBreakpoint
  6996.  * ------------------------------------------------------------------------- */
  6997.  
  6998. void DebuggerBreakpoint::CommonCtor()
  6999. {
  7000.     m_next = NULL;
  7001.     m_id = 0;
  7002.     m_name = NULL;
  7003.     m_active = false;
  7004.     m_managed = false;
  7005.     m_doc = NULL;
  7006.     m_process = NULL;
  7007.     m_address= 0;
  7008.     m_patchedValue = 0;
  7009.     m_skipThread = 0;
  7010.     m_unmanagedModuleBase = 0;
  7011.     m_pModuleList = NULL;
  7012. }
  7013.  
  7014. DebuggerBreakpoint::DebuggerBreakpoint(const WCHAR *name, SIZE_T nameLength, 
  7015.                                        SIZE_T index, DWORD threadID)
  7016.     : m_threadID(threadID), m_index(index)
  7017. {
  7018.     CommonCtor();
  7019.     
  7020.     // Make a copy of the name
  7021.     if (nameLength > 0)
  7022.     {
  7023.         // check to see if the name contains the "!" character. 
  7024.         // Anything before the "!" is a module name and will not
  7025.         // be stored in the breakpoint name
  7026.         WCHAR *szModuleEnd = wcschr(name, L'!');
  7027.         if (szModuleEnd != NULL)
  7028.         {
  7029.             name = szModuleEnd+1;
  7030.  
  7031.             nameLength = wcslen (name);
  7032.         }
  7033.  
  7034.         m_name = new WCHAR[nameLength+1];
  7035.         _ASSERTE(m_name != NULL);
  7036.  
  7037.         wcsncpy(m_name, name, nameLength);
  7038.         m_name[nameLength] = 0;
  7039.     }
  7040.  
  7041.     Init(NULL, false);
  7042. }
  7043.  
  7044. DebuggerBreakpoint::DebuggerBreakpoint(DebuggerFunction *f, 
  7045.                                        SIZE_T offset, DWORD threadID)
  7046.     : m_threadID(threadID), m_index(offset)
  7047. {
  7048.     CommonCtor();
  7049.     
  7050.     SIZE_T len = wcslen(f->m_name) + 1;
  7051.  
  7052.     if (f->m_className != NULL)
  7053.         len += wcslen(f->m_className) + 2;
  7054.  
  7055.     m_name = new WCHAR[len];
  7056.  
  7057.     if (f->m_className != 0)
  7058.     {
  7059.         wcscpy(m_name, f->m_className);
  7060.         wcscat(m_name, L"::");
  7061.         wcscat(m_name, f->m_name);
  7062.     }
  7063.     else
  7064.         wcscpy(m_name, f->m_name);
  7065.  
  7066.     Init(f->m_module, true);
  7067. }
  7068.  
  7069.  
  7070. DebuggerBreakpoint::DebuggerBreakpoint(DebuggerSourceFile *file, 
  7071.                                        SIZE_T lineNumber, DWORD threadID)
  7072.     : m_threadID(threadID), m_index(lineNumber)
  7073. {
  7074.     CommonCtor();
  7075.     
  7076.     // Copy the filename
  7077.     m_name = new WCHAR[wcslen(file->m_name) + 1];
  7078.     wcscpy(m_name, file->m_name);
  7079.  
  7080.     // Init the breakpoint
  7081.     Init(file->m_module, true);
  7082. }
  7083.  
  7084.  
  7085. DebuggerBreakpoint::~DebuggerBreakpoint()
  7086. {
  7087.     if (m_active)
  7088.         Deactivate();
  7089.  
  7090.     if (m_name != NULL)
  7091.         delete [] m_name;
  7092.  
  7093.     // Remove itself from the shell's list of breakpoints
  7094.     DebuggerBreakpoint **bp = &g_pShell->m_breakpoints;
  7095.     while (*bp != this)
  7096.         bp = &(*bp)->m_next;
  7097.  
  7098.     while (m_pModuleList)
  7099.         RemoveBoundModule(m_pModuleList->m_pModule);
  7100.  
  7101.     *bp = m_next;
  7102. }
  7103.  
  7104. void DebuggerBreakpoint::Init(DebuggerModule *module, bool bProceed)
  7105. {
  7106.     bool        bFound = false;
  7107.     m_id = ++g_pShell->m_lastBreakpointID;
  7108.  
  7109.     m_next = g_pShell->m_breakpoints;
  7110.     g_pShell->m_breakpoints = this;
  7111.  
  7112.     if (bProceed == false)
  7113.         return;
  7114.  
  7115.     if (module != NULL && !IsBoundToModule(module))
  7116.     {
  7117.         bFound = Bind(module, NULL);
  7118.  
  7119.         if (!bFound)
  7120.             bFound = BindUnmanaged(g_pShell->m_currentProcess);
  7121.     }
  7122.  
  7123.     if (bFound)
  7124.         g_pShell->OnBindBreakpoint(this, module);
  7125.  
  7126. }
  7127.  
  7128. bool DebuggerBreakpoint::BindUnmanaged(ICorDebugProcess *process,
  7129.                                        DWORD moduleBase)
  7130. {
  7131.     if (m_name == NULL)
  7132.         return FALSE;
  7133.  
  7134.     if (m_process != NULL || process == NULL)
  7135.         return FALSE;
  7136.  
  7137.     IMAGEHLP_SYMBOL *sym = (IMAGEHLP_SYMBOL*) _alloca(sizeof(sym) +
  7138.                                                       256);
  7139.     sym->SizeOfStruct = sizeof(sym) + 256;
  7140.     sym->MaxNameLength = 256;
  7141.     
  7142.     MAKE_ANSIPTR_FROMWIDE(symbolName, m_name);
  7143.  
  7144.     HANDLE hProcess;
  7145.     HRESULT hr = process->GetHandle(&hProcess);
  7146.     if (FAILED(hr))
  7147.     {
  7148.         g_pShell->ReportError(hr);
  7149.         return false;
  7150.     }
  7151.             
  7152.     BOOL succ;
  7153.     succ = SymGetSymFromName(hProcess, symbolName, sym);
  7154.  
  7155.     if (!succ)
  7156.         return false;
  7157.  
  7158.     // Find the base of the module that this symbol is in.
  7159.     if (moduleBase == 0)
  7160.     {
  7161.         moduleBase = SymGetModuleBase(hProcess, sym->Address);
  7162.  
  7163.         if (moduleBase == 0)
  7164.         {
  7165.             g_pShell->ReportError(HRESULT_FROM_WIN32(GetLastError()));
  7166.             return false;
  7167.         }
  7168.     }
  7169.     
  7170.     m_managed = false;
  7171.     m_process = process;
  7172.     m_address = sym->Address + m_index;
  7173.     m_unmanagedModuleBase = moduleBase;
  7174.  
  7175.     if (m_active)
  7176.         ApplyUnmanagedPatch();
  7177.  
  7178.     return true;
  7179. }
  7180.  
  7181. bool DebuggerBreakpoint::Bind(DebuggerModule *module, ISymUnmanagedDocument *doc)
  7182. {
  7183.     if (m_name == NULL)
  7184.         return (false);
  7185.  
  7186.     // Make sure we are not double-binding
  7187.     _ASSERTE(!IsBoundToModule(module));
  7188.  
  7189. #if 0    
  7190.     if (m_module != NULL)
  7191.         return (false);
  7192. #endif    
  7193.  
  7194.     //
  7195.     // First, see if our name is a function name
  7196.     //
  7197.  
  7198.     bool success = false;
  7199.     HRESULT hr = S_OK;
  7200.  
  7201.     WCHAR *classEnd = wcschr(m_name, L':');
  7202.     if (classEnd != NULL && classEnd[1] == L':')
  7203.     {
  7204.         //
  7205.         // Name is class::method.
  7206.         //
  7207.  
  7208.         WCHAR *method = classEnd + 2;
  7209.  
  7210.         *classEnd = 0;
  7211.         mdTypeDef td = mdTypeDefNil;
  7212.  
  7213.         // Only try to lookup the class if we have a name for one.
  7214.         if (classEnd != m_name)
  7215.             hr = g_pShell->FindTypeDefByName(module, m_name, &td);
  7216.  
  7217.         // Its okay if we have a nil typedef since that simply
  7218.         // indicates a global function.
  7219.         if (SUCCEEDED(hr))
  7220.         {
  7221.             HCORENUM e = NULL;
  7222.             mdMethodDef md;
  7223.             ULONG count;
  7224.  
  7225.             while (TRUE)
  7226.             {
  7227.                 hr = module->GetMetaData()->EnumMethodsWithName(&e, td, method,
  7228.                                                                 &md, 1,
  7229.                                                                 &count);
  7230.                 if (FAILED(hr) || count == 0)
  7231.                     break;
  7232.  
  7233.                 DebuggerFunction *function = module->ResolveFunction(md, NULL);
  7234.                 if (function == NULL)
  7235.                     break;
  7236.  
  7237.                 //
  7238.                 // Assume offset is IL only for functions which have 
  7239.                 // no native code.
  7240.                 // 
  7241.                 // !!! This will be wrong if we're rebinding a breakpoint, 
  7242.                 // and we don't have native code because the jit hasn't 
  7243.                 // occurred yet.
  7244.                 //
  7245.  
  7246.                 bool il;
  7247.  
  7248.                 ICorDebugCode *icode;
  7249.                 hr = function->m_ifunction->GetNativeCode(&icode);
  7250.                 if ((SUCCEEDED(hr) || hr == CORDBG_E_CODE_NOT_AVAILABLE)
  7251.                     && icode != NULL)
  7252.                 {
  7253.                     RELEASE(icode);
  7254.                     il = FALSE;
  7255.                 }
  7256.                 else
  7257.                     il = TRUE;
  7258.  
  7259.                 if (SUCCEEDED(function->LoadCode(!il)))
  7260.                 {
  7261.                     //
  7262.                     // Our instruction validation fails if we can't load the
  7263.                     // code at this point.  For now, just let it slide.
  7264.                     // 
  7265.  
  7266.                     if (!function->ValidateInstruction(!il, m_index))
  7267.                         break;
  7268.                 }
  7269.  
  7270.                 DebuggerCodeBreakpoint *bp = 
  7271.                     new DebuggerCodeBreakpoint(m_id, module, 
  7272.                                                function, m_index, il,
  7273.                                                NULL_THREAD_ID);
  7274.  
  7275.                 if (bp == NULL)
  7276.                 {
  7277.                     g_pShell->ReportError(E_OUTOFMEMORY);
  7278.                     return (false);
  7279.                 }
  7280.  
  7281.                 if (m_active)
  7282.                     bp->Activate();
  7283.  
  7284.                 success = true;
  7285.             }
  7286.         }
  7287.  
  7288.         *classEnd = L':';
  7289.     }
  7290.  
  7291.     if (!success)
  7292.     {
  7293.         if ((doc == NULL) && (module->GetSymbolReader() != NULL))
  7294.         {
  7295.             // Get the source file token by name
  7296.             GUID g = {0};
  7297.             HRESULT hr = module->GetSymbolReader()->GetDocument(m_name,
  7298.                                                                 g, g, g,
  7299.                                                                 &doc);
  7300.  
  7301.             // If the source file wasn't found, see if we can find it using
  7302.             // the short name, since the meta data stores only relative paths.
  7303.             if (hr != S_OK)
  7304.             {
  7305.                 char        rcFile[MAX_PATH];
  7306.                 char        rcExt[64];
  7307.  
  7308.                 MAKE_ANSIPTR_FROMWIDE(nameA, m_name);
  7309.                 _splitpath(nameA, NULL, NULL, rcFile, rcExt);
  7310.                 strcat(rcFile, rcExt);
  7311.  
  7312.                 MAKE_WIDEPTR_FROMUTF8(nameW, rcFile);
  7313.                 hr = module->GetSymbolReader()->GetDocument(nameW,
  7314.                                                             g, g, g,
  7315.                                                             &doc);
  7316.             }
  7317.         }
  7318.  
  7319.  
  7320.         if ((hr == S_OK) && (doc != NULL))
  7321.         {
  7322.             DebuggerSourceFile *file = module->ResolveSourceFile(doc);
  7323.             _ASSERTE(file != NULL);
  7324.  
  7325.             //
  7326.             // !!! May want to try to adjust line number rather than just
  7327.             // having the binding fail.
  7328.             //
  7329.  
  7330.             if (file->FindClosestLine(m_index, false) == m_index)
  7331.             {
  7332.                 DebuggerSourceCodeBreakpoint *bp = 
  7333.                     new DebuggerSourceCodeBreakpoint(m_id, file, m_index, 
  7334.                                                      NULL_THREAD_ID);
  7335.  
  7336.                 if (bp == NULL)
  7337.                 {
  7338.                     g_pShell->ReportError(E_OUTOFMEMORY);
  7339.                     return (false);
  7340.                 } else if (bp->m_function == NULL)
  7341.                     return false;
  7342.                 
  7343.                 if (m_active)
  7344.                     bp->Activate();
  7345.  
  7346.                 m_doc = doc;
  7347.  
  7348.                 success = true;
  7349.             }
  7350.         }
  7351.     }
  7352.  
  7353.     if (success)
  7354.     {
  7355.         m_managed = true;
  7356.  
  7357.         if (!IsBoundToModule(module))
  7358.             AddBoundModule(module);
  7359.     }
  7360.  
  7361.     return (success);
  7362. }
  7363.  
  7364. void DebuggerBreakpoint::Unbind()
  7365. {
  7366.     if (m_managed)
  7367.     {
  7368.         while (m_pModuleList != NULL)
  7369.         {
  7370.             DebuggerCodeBreakpoint *bp = m_pModuleList->m_pModule->m_breakpoints;
  7371.  
  7372.             while (bp != NULL)
  7373.             {
  7374.                 g_pShell->OnUnBindBreakpoint(this, m_pModuleList->m_pModule);
  7375.                 DebuggerCodeBreakpoint *bpNext = bp->m_next;
  7376.                 delete bp;
  7377.                 bp = bpNext;
  7378.             }
  7379.  
  7380.             // Remove the module from the list
  7381.             RemoveBoundModule(m_pModuleList->m_pModule);
  7382.         }
  7383.     }
  7384.     else
  7385.     {
  7386.         if (m_process != 0)
  7387.             UnapplyUnmanagedPatch();
  7388.  
  7389.         m_process = NULL;
  7390.     }
  7391. }
  7392.  
  7393. void DebuggerBreakpoint::Activate()
  7394. {
  7395.     if (m_active)
  7396.         return;
  7397.  
  7398.     if (m_managed)
  7399.     {
  7400.         BreakpointModuleNode *pCurNode = m_pModuleList;
  7401.         
  7402.         while (pCurNode != NULL)
  7403.         {
  7404.             DebuggerCodeBreakpoint *bp = pCurNode->m_pModule->m_breakpoints;
  7405.  
  7406.             while (bp != NULL)
  7407.             {
  7408.                 if (bp->m_id == m_id)
  7409.                 {
  7410.                     bp->Activate();
  7411.                     g_pShell->OnActivateBreakpoint(this);
  7412.                 }
  7413.                 bp = bp->m_next;
  7414.             }
  7415.             
  7416.             pCurNode = pCurNode->m_pNext;
  7417.         }
  7418.     }
  7419.     else
  7420.         if (m_process)
  7421.             ApplyUnmanagedPatch();
  7422.  
  7423.     m_active = true;
  7424. }
  7425.  
  7426. void DebuggerBreakpoint::Deactivate()
  7427. {
  7428.     if (!m_active)
  7429.         return;
  7430.  
  7431.     if (m_managed)
  7432.     {
  7433.         BreakpointModuleNode *pCurNode = m_pModuleList;
  7434.  
  7435.         while (pCurNode != NULL)
  7436.         {
  7437.             DebuggerCodeBreakpoint *bp = pCurNode->m_pModule->m_breakpoints;
  7438.  
  7439.             while (bp != NULL)
  7440.             {
  7441.                 if (bp->m_id == m_id)
  7442.                 {
  7443.                     bp->Deactivate();
  7444.                     g_pShell->OnDeactivateBreakpoint(this);
  7445.                 }
  7446.                 bp = bp->m_next;
  7447.             }
  7448.  
  7449.             pCurNode = pCurNode->m_pNext;
  7450.         }
  7451.     }
  7452.     else
  7453.     {
  7454.         if (m_process != 0)
  7455.             UnapplyUnmanagedPatch();
  7456.     }
  7457.  
  7458.     m_active = false;
  7459. }
  7460.  
  7461. void DebuggerBreakpoint::Detach()
  7462. {
  7463.     if (m_managed)
  7464.     {
  7465.         BreakpointModuleNode *pCurNode = m_pModuleList;
  7466.  
  7467.         while (pCurNode != NULL)
  7468.         {
  7469.             DebuggerCodeBreakpoint *bp = pCurNode->m_pModule->m_breakpoints;
  7470.  
  7471.             while (bp != NULL)
  7472.             {
  7473.                 if (bp->m_id == m_id)
  7474.                 {
  7475.                     bp->Deactivate();
  7476.                 }
  7477.                 bp = bp->m_next;
  7478.             }
  7479.  
  7480.             pCurNode = pCurNode->m_pNext;
  7481.         }
  7482.     }
  7483.     else
  7484.     {
  7485.         if (m_process != 0)
  7486.             UnapplyUnmanagedPatch();
  7487.     }
  7488. }
  7489.  
  7490. void DebuggerBreakpoint::Attach()
  7491. {
  7492.     if (m_managed)
  7493.     {
  7494.         BreakpointModuleNode *pCurNode = m_pModuleList;
  7495.  
  7496.         while (pCurNode != NULL)
  7497.         {
  7498.             DebuggerCodeBreakpoint *bp = pCurNode->m_pModule->m_breakpoints;
  7499.  
  7500.             while (bp != NULL)
  7501.             {
  7502.                 if (bp->m_id == m_id)
  7503.                 {
  7504.                     bp->Activate();
  7505.                 }
  7506.                 bp = bp->m_next;
  7507.             }
  7508.  
  7509.             pCurNode = pCurNode->m_pNext;
  7510.         }
  7511.     }
  7512.     else
  7513.     {
  7514.         if (m_process != 0)
  7515.             ApplyUnmanagedPatch();
  7516.     }
  7517. }
  7518.  
  7519. bool DebuggerBreakpoint::Match(ICorDebugBreakpoint *ibreakpoint)
  7520. {
  7521.     if (m_managed)
  7522.     {
  7523.         BreakpointModuleNode *pCurNode = m_pModuleList;
  7524.  
  7525.         while (pCurNode != NULL)
  7526.         {
  7527.             DebuggerCodeBreakpoint *bp = pCurNode->m_pModule->m_breakpoints;
  7528.  
  7529.             while (bp != NULL)
  7530.             {
  7531.                 if (bp->m_id == m_id && bp->Match(ibreakpoint))
  7532.                     return (true);
  7533.                 bp = bp->m_next;
  7534.             }
  7535.  
  7536.             pCurNode = pCurNode->m_pNext;
  7537.         }
  7538.     }
  7539.  
  7540.     return false;
  7541. }
  7542.  
  7543. bool DebuggerBreakpoint::MatchUnmanaged(CORDB_ADDRESS address)
  7544. {
  7545.     return !m_managed && m_process != NULL && m_address == address;
  7546. }
  7547.  
  7548. void DebuggerBreakpoint::ApplyUnmanagedPatch()
  7549. {
  7550.     SIZE_T read = 0;
  7551.  
  7552.     if (m_address == NULL)
  7553.     {
  7554.         g_pShell->Write( L"Unable to set unmanaged breakpoint at 0x00000000\n" );
  7555.         return;
  7556.     }
  7557.  
  7558.     HRESULT hr = m_process->ReadMemory(m_address, 1, &m_patchedValue, &read);
  7559.     if (FAILED(hr) )
  7560.     {
  7561.         g_pShell->ReportError(hr);
  7562.         return;
  7563.     }
  7564.  
  7565.     if (read != 1 )
  7566.     {
  7567.         g_pShell->Write( L"Unable to read memory\n" );
  7568.         return;
  7569.     }
  7570.  
  7571.     BYTE patchByte = 0xCC;
  7572.     hr = m_process->WriteMemory(m_address, 1, &patchByte, &read);
  7573.     if (FAILED(hr) )
  7574.         g_pShell->ReportError(hr);
  7575.  
  7576.     if (read != 1 )
  7577.     {
  7578.         g_pShell->Write( L"Unable to write memory\n" );
  7579.         return;
  7580.     }
  7581. }
  7582.  
  7583. void DebuggerBreakpoint::UnapplyUnmanagedPatch()
  7584. {
  7585.     SIZE_T written;
  7586.  
  7587.     if (m_address == NULL)
  7588.         return;
  7589.  
  7590.     HRESULT hr = m_process->WriteMemory(m_address, 1,
  7591.                                         &m_patchedValue,&written);
  7592.     if (FAILED(hr))
  7593.         g_pShell->ReportError(hr);
  7594.  
  7595.     if (written != 1 )
  7596.         g_pShell->Write( L"Unable to write memory!\n" );
  7597. }
  7598.  
  7599.  
  7600. void DebuggerBreakpoint::ChangeSourceFile (WCHAR *filename)
  7601. {
  7602.     // first, check to see if the file even exists. Otherwise error out.
  7603.     MAKE_ANSIPTR_FROMWIDE (fnameA, filename);
  7604.     _ASSERTE (fnameA != NULL);
  7605.  
  7606.     FILE *stream = fopen (fnameA, "r");
  7607.     DebuggerSourceFile *pSource = NULL;
  7608.  
  7609.     if (stream != NULL)
  7610.     {
  7611.         fclose (stream);
  7612.  
  7613.         if (m_managed)
  7614.         {
  7615.             BreakpointModuleNode *pCurNode = m_pModuleList;
  7616.  
  7617.             while (pCurNode != NULL)
  7618.             {
  7619.                 if ((m_doc == NULL) &&
  7620.                     (pCurNode->m_pModule->GetSymbolReader() != NULL))
  7621.                 {
  7622.                     // Get the source file token by name
  7623.                     GUID g = {0};
  7624.                     ISymUnmanagedDocument *doc = NULL;
  7625.                     HRESULT hr = pCurNode->m_pModule->GetSymbolReader()->GetDocument(filename,
  7626.                                                                         g, g, g,
  7627.                                                                         &doc);
  7628.  
  7629.                     // If the source file wasn't found, see if we can find it using
  7630.                     // the short name, since the meta data stores only relative paths.
  7631.                     if (hr == CLDB_E_RECORD_NOTFOUND)
  7632.                     {
  7633.                         char        rcFile[MAX_PATH];
  7634.                         char        rcExt[64];
  7635.  
  7636.                         MAKE_ANSIPTR_FROMWIDE(nameA, filename);
  7637.                         _splitpath(nameA, NULL, NULL, rcFile, rcExt);
  7638.                         strcat(rcFile, rcExt);
  7639.  
  7640.                         MAKE_WIDEPTR_FROMUTF8(nameW, rcFile);
  7641.                         hr = pCurNode->m_pModule->GetSymbolReader()->GetDocument(nameW,
  7642.                                                                     g, g, g,
  7643.                                                                     &doc);
  7644.  
  7645.                     }
  7646.  
  7647.                     m_doc = doc;
  7648.                 }
  7649.  
  7650.                 if (m_doc != NULL)
  7651.                 {
  7652.                     if ((pSource = pCurNode->m_pModule->ResolveSourceFile (m_doc)) != NULL)
  7653.                     {
  7654.                         pSource->ReloadText (filename, true);
  7655.                     }
  7656.                 }
  7657.                 else
  7658.                 {
  7659.                     g_pShell->Write(L"Could not associate the given source file.\n");
  7660.                     g_pShell->Write(L"Please check that the file name (and path) was entered correctly.\n");
  7661.                     g_pShell->Write(L"This problem could also arise if files were compiled without the debug flag.\n");
  7662.  
  7663.                 }
  7664.  
  7665.                 pCurNode = pCurNode->m_pNext;
  7666.             }
  7667.         }
  7668.     }
  7669.     else
  7670.     {
  7671.         g_pShell->Write(L"Could not locate/open given file.\n");
  7672.     }
  7673. }
  7674.  
  7675.  
  7676.  
  7677. void DebuggerBreakpoint::UpdateName (WCHAR *pstrName)
  7678. {
  7679.     // save the old name just in case we run out of memory
  7680.     // while allocating memory for the new name
  7681.     WCHAR *pTemp = m_name;
  7682.     int iLength = wcslen (pstrName);
  7683.  
  7684.     if ((m_name = new WCHAR [iLength+1]) != NULL)
  7685.     {
  7686.         wcscpy (m_name, pstrName);
  7687.         delete [] pTemp;
  7688.     }
  7689.     else
  7690.         m_name = pTemp;
  7691.  
  7692. }
  7693.  
  7694. // This will return true if this breakpoint is associated
  7695. // with the pModule argument
  7696. bool DebuggerBreakpoint::IsBoundToModule(DebuggerModule *pModule)
  7697. {
  7698.     for (BreakpointModuleNode *pCur = m_pModuleList; pCur != NULL; pCur = pCur->m_pNext)
  7699.     {
  7700.         if (pCur->m_pModule == pModule)
  7701.             return (true);
  7702.     }
  7703.  
  7704.     return (false);
  7705. }
  7706.  
  7707. bool DebuggerBreakpoint::AddBoundModule(DebuggerModule *pModule)
  7708. {
  7709.     // Make sure we don't add it twice.
  7710.     if (IsBoundToModule(pModule))
  7711.         return (false);
  7712.  
  7713.     // Create new node
  7714.     BreakpointModuleNode *pNewNode = new BreakpointModuleNode;
  7715.     _ASSERTE(pNewNode != NULL && "Out of memory!!!");
  7716.  
  7717.     // OOM?
  7718.     if (!pNewNode)
  7719.         return (false);
  7720.  
  7721.     // Tack it onto the front of the list
  7722.     pNewNode->m_pModule = pModule;
  7723.     pNewNode->m_pNext = m_pModuleList;
  7724.     m_pModuleList = pNewNode;
  7725.  
  7726.     // Indicate success
  7727.     return (true);
  7728. }
  7729.  
  7730. bool DebuggerBreakpoint::RemoveBoundModule(DebuggerModule *pModule)
  7731. {
  7732.     if (!IsBoundToModule(pModule))
  7733.         return (false);
  7734.  
  7735.     // Find the module in the list
  7736.     for (BreakpointModuleNode **ppCur = &m_pModuleList;
  7737.         *ppCur != NULL && (*ppCur)->m_pModule != pModule;
  7738.         ppCur = &((*ppCur)->m_pNext));
  7739.  
  7740.     _ASSERTE(*ppCur != NULL);
  7741.  
  7742.     // Remove the module from the list
  7743.     BreakpointModuleNode *pDel = *ppCur;
  7744.     *ppCur = pDel->m_pNext;
  7745.     pDel->m_pModule = NULL;
  7746.     pDel->m_pNext = NULL;
  7747.     delete pDel;
  7748.  
  7749.     return (true);
  7750. }
  7751.  
  7752.  
  7753. /* ------------------------------------------------------------------------- *
  7754.  * Debugger FilePathCache
  7755.  * ------------------------------------------------------------------------- */
  7756.  
  7757. // This function looks for an existing "foo.deb" file and reads in the 
  7758. // contents and fills the structures.
  7759. HRESULT DebuggerFilePathCache::Init (void)
  7760. {
  7761.     int i=0;
  7762.  
  7763.     // Set the path elements from the current path.
  7764.     _ASSERTE (g_pShell->m_currentSourcesPath != NULL);
  7765.  
  7766.     WCHAR *pszTemp;
  7767.  
  7768.     if ((pszTemp = new WCHAR [wcslen(g_pShell->m_currentSourcesPath)+1]) != NULL)
  7769.     {
  7770.         wcscpy (pszTemp, g_pShell->m_currentSourcesPath);
  7771.         g_pShell->UpdateCurrentPath (pszTemp);
  7772.         delete [] pszTemp;
  7773.     }
  7774.  
  7775.     // free up the cache
  7776.     for (i=0; i<m_iCacheCount; i++)
  7777.     {
  7778.         delete [] m_rpstrModName [i];
  7779.         delete [] m_rpstrFullPath [i];
  7780.  
  7781.         m_rpstrModName [i] = NULL;
  7782.         m_rpstrFullPath [i] = NULL;
  7783.         m_rDocs [i] = NULL;
  7784.     }
  7785.  
  7786.     m_iCacheCount = 0;
  7787.  
  7788.     return S_OK;
  7789. }
  7790.  
  7791. // This function is used for separating out the individual paths
  7792. // from the passed path string
  7793. HRESULT    DebuggerFilePathCache::InitPathArray (WCHAR *pstrName)
  7794. {
  7795.     bool bDone = false;
  7796.     int iBegin;
  7797.     int iEnd;
  7798.     int iCounter = 0;
  7799.     int iIndex = 0;
  7800.  
  7801.     // first, free the existing array members (if any)
  7802.     while (m_iPathCount-- > 0)
  7803.     {
  7804.         delete [] m_rstrPath [m_iPathCount];
  7805.         m_rstrPath [m_iPathCount] = NULL;
  7806.     }
  7807.  
  7808.     MAKE_ANSIPTR_FROMWIDE(nameA, pstrName);
  7809.     _ASSERTE (nameA != NULL);
  7810.     if (nameA == NULL)
  7811.         return (E_OUTOFMEMORY);
  7812.  
  7813.  
  7814.     while (bDone == false)
  7815.     {
  7816.         iBegin = iCounter;
  7817.         while ((nameA [iCounter] != ';') && (nameA [iCounter] != '\0'))
  7818.             iCounter++;
  7819.  
  7820.         if (nameA [iCounter] == '\0')
  7821.             bDone = true;
  7822.  
  7823.         iEnd = iCounter++;
  7824.  
  7825.         if (iEnd != iBegin)
  7826.         {
  7827.             int iStrLen = iEnd - iBegin;
  7828.  
  7829.             _ASSERTE (iStrLen > 0);
  7830.             _ASSERTE (iIndex < MAX_PATH_ELEMS);
  7831.             if ((m_rstrPath [iIndex] = new CHAR [iStrLen + 1]) != NULL)
  7832.             {
  7833.                 // copy the extracted string
  7834.                 strncpy (m_rstrPath [iIndex], &(nameA [iBegin]), iStrLen);
  7835.  
  7836.                 // null terminate
  7837.                 m_rstrPath [iIndex][iStrLen] = L'\0';
  7838.  
  7839.                 iIndex++;
  7840.             }
  7841.             else
  7842.                 return (E_OUTOFMEMORY);
  7843.         }
  7844.     }
  7845.  
  7846.     m_iPathCount = iIndex;
  7847.  
  7848.     return (S_OK);
  7849. }
  7850.  
  7851.  
  7852.  
  7853. int    DebuggerFilePathCache::GetFileFromCache(DebuggerModule *pModule,
  7854.                                             ISymUnmanagedDocument *doc, 
  7855.                                             CHAR **ppstrFName)
  7856. {
  7857.     *ppstrFName = NULL;
  7858.     if ((m_iCacheCount == 0) || (pModule == NULL) || !doc)
  7859.         return -1;
  7860.  
  7861.     for (int i=0; i<m_iCacheCount; i++)
  7862.     {
  7863.  
  7864.         if (m_rDocs [i] == doc)
  7865.         {
  7866.             // check if the module names also match
  7867.  
  7868.             // allocate memory and store the data
  7869.             WCHAR strModuleName [MAX_PATH+1];
  7870.             ULONG32 NameLength;
  7871.  
  7872.             // Initialize module name to null
  7873.             strModuleName [0] = L'\0';
  7874.  
  7875.             // Now get the module name
  7876.             pModule ->GetICorDebugModule()->GetName(MAX_PATH, &NameLength, strModuleName);
  7877.  
  7878.             // Convert module name to ANSI and store
  7879.             MAKE_ANSIPTR_FROMWIDE (ModNameA, strModuleName);
  7880.             _ASSERTE (ModNameA != NULL);
  7881.  
  7882.             // Convert the module name to lowercae before comparing
  7883.             char *pszTemp = ModNameA;
  7884.  
  7885.             while (*pszTemp != '\0')
  7886.             {
  7887.                 *pszTemp = tolower (*pszTemp);
  7888.                 pszTemp++;
  7889.             }
  7890.  
  7891.             if (!strcmp (ModNameA, m_rpstrModName [i]))
  7892.             {
  7893.                 // The names match. So return the source file name
  7894.                 _ASSERTE (m_rpstrFullPath[i] != NULL);
  7895.                 if ((*ppstrFName = new char [strlen(m_rpstrFullPath[i]) + 1]) != NULL)
  7896.                 {
  7897.                     strcpy (*ppstrFName, m_rpstrFullPath[i]);
  7898.                 }
  7899.  
  7900.                 // found it. So exit loop.
  7901.                 return (i);
  7902.             }
  7903.         }
  7904.     }
  7905.  
  7906.     return (-1);
  7907. }
  7908.  
  7909.  
  7910. BOOL    DebuggerFilePathCache::UpdateFileCache (DebuggerModule *pModule, 
  7911.                                                 ISymUnmanagedDocument *doc,
  7912.                                                 CHAR *pFullPath)
  7913. {
  7914.     char *pszString;
  7915.  
  7916.     // first, convert the file name to lowercase
  7917.     char *pTemp = pFullPath;
  7918.  
  7919.     if (pTemp)
  7920.     {
  7921.         while (*pTemp)
  7922.         {
  7923.             *pTemp = tolower (*pTemp);
  7924.             pTemp++;
  7925.         }
  7926.     }
  7927.  
  7928.     // check if this is an addition or modification
  7929.     int iCacheIndex = GetFileFromCache (pModule, doc, &pszString);
  7930.  
  7931.     if (iCacheIndex != -1)
  7932.     {
  7933.  
  7934.         delete [] pszString;
  7935.  
  7936.         // if the names match, then no need to do anything. Simply return!
  7937.         if (!strcmp (pFullPath, pszString))
  7938.             return true;
  7939.  
  7940.         _ASSERTE (iCacheIndex < m_iCacheCount);
  7941.         // an entry already exists - so update it
  7942.  
  7943.         // first, delete the existing path
  7944.         delete [] m_rpstrFullPath [iCacheIndex];
  7945.  
  7946.         if ((m_rpstrFullPath [iCacheIndex] = new char [strlen (pFullPath) +1]) == NULL)
  7947.         {
  7948.             // free up the memory allocated for module name
  7949.             delete [] m_rpstrModName [iCacheIndex];
  7950.             m_rpstrModName [iCacheIndex] = NULL;
  7951.             m_rDocs [iCacheIndex] = NULL;
  7952.             return false;
  7953.         }
  7954.  
  7955.         strcpy (m_rpstrFullPath [iCacheIndex], pFullPath);
  7956.         return true;
  7957.     }
  7958.     
  7959.     // Create a new entry
  7960.     if (pFullPath)
  7961.     {
  7962.         if (m_iCacheCount < MAX_CACHE_ELEMS)
  7963.         {
  7964.             m_rpstrModName [m_iCacheCount] = NULL;
  7965.             m_rpstrFullPath [m_iCacheCount] = NULL;
  7966.             m_rDocs [m_iCacheCount] = NULL;
  7967.  
  7968.             // allocate memory and store the data
  7969.             WCHAR strModuleName [MAX_PATH+1];
  7970.             ULONG32 NameLength;
  7971.  
  7972.             // Initialize module name to null
  7973.             strModuleName [0] = L'\0';
  7974.  
  7975.             // Now get the module name
  7976.             pModule ->GetICorDebugModule()->GetName(MAX_PATH, &NameLength, strModuleName);
  7977.  
  7978.             // Convert module name to ANSI and store
  7979.             MAKE_ANSIPTR_FROMWIDE (ModNameA, strModuleName);
  7980.             _ASSERTE (ModNameA != NULL);
  7981.  
  7982.             if ((m_rpstrModName [m_iCacheCount] = new char [strlen (ModNameA) +1]) == NULL)
  7983.                 return false;
  7984.  
  7985.             strcpy (m_rpstrModName[m_iCacheCount], ModNameA);
  7986.  
  7987.             // convert the module name to lowercase
  7988.             char *pszTemp = m_rpstrModName [m_iCacheCount];
  7989.             while (*pszTemp != '\0')
  7990.             {
  7991.                 *pszTemp = tolower (*pszTemp);
  7992.                 pszTemp++;
  7993.             }
  7994.  
  7995.             // Also store full pathname and document
  7996.             if ((m_rpstrFullPath [m_iCacheCount] = new char [strlen (pFullPath) +1]) == NULL)
  7997.             {
  7998.                 // free up the memory alloacted for module name
  7999.                 delete [] m_rpstrModName [m_iCacheCount];
  8000.                 m_rpstrModName [m_iCacheCount] = NULL;
  8001.                 return false;
  8002.             }
  8003.  
  8004.             strcpy (m_rpstrFullPath [m_iCacheCount], pFullPath);
  8005.  
  8006.             m_rDocs [m_iCacheCount] = doc;
  8007.             doc->AddRef();
  8008.  
  8009.             m_iCacheCount++;
  8010.  
  8011.         }
  8012.         else
  8013.             return false;
  8014.     }
  8015.  
  8016.     return true;
  8017. }
  8018.  
  8019.  
  8020.  
  8021. // This sets the full file name as well as the stripped file name
  8022. BOOL    ModuleSourceFile::SetFullFileName (ISymUnmanagedDocument *doc,
  8023.                                            LPCSTR pstrFullFileName)
  8024. {
  8025.  
  8026.     m_SFDoc = doc;
  8027.     m_SFDoc->AddRef();
  8028.  
  8029.     int iLen = MultiByteToWideChar (CP_ACP, 0, pstrFullFileName, -1, NULL, 0); 
  8030.  
  8031.     m_pstrFullFileName = new WCHAR [iLen];
  8032.  
  8033.     _ASSERTE (m_pstrFullFileName != NULL);
  8034.  
  8035.     if (m_pstrFullFileName)
  8036.     {
  8037.         if (MultiByteToWideChar (CP_ACP, 0, pstrFullFileName, -1, m_pstrFullFileName, iLen))
  8038.         {
  8039.             // strip the path and store just the lowercase file name
  8040.             WCHAR        rcFile[MAX_PATH];
  8041.             WCHAR        rcExt[MAX_EXT];
  8042.  
  8043.             _wsplitpath(m_pstrFullFileName, NULL, NULL, rcFile, rcExt);
  8044.             wcscat(rcFile, rcExt);
  8045.             iLen = wcslen (rcFile);
  8046.  
  8047.             m_pstrStrippedFileName = new WCHAR [iLen + 1];
  8048.  
  8049.             wcscpy(m_pstrStrippedFileName, rcFile);
  8050.         }
  8051.         else
  8052.             return false;
  8053.     }
  8054.     else
  8055.         return false;
  8056.  
  8057.     return true;
  8058. }
  8059.  
  8060.  
  8061.