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

  1. #include "stdafx.h"
  2.  
  3. #define BUF_SIZE 256
  4.  
  5. /* ------------------------------------------------------------------------- *
  6.  * Debugger base class
  7.  * ------------------------------------------------------------------------- */
  8.  
  9. DebuggerHashTable::~DebuggerHashTable()
  10. {
  11.     HASHFIND    find;
  12.  
  13.     for (DebuggerHashEntry *entry = (DebuggerHashEntry *) FindFirstEntry(&find);
  14.         entry != NULL;
  15.         entry = (DebuggerHashEntry *) FindNextEntry(&find))
  16.         delete entry->pBase;
  17. }
  18.  
  19. HRESULT DebuggerHashTable::AddBase(DebuggerBase *pBase)
  20. {
  21.     if (!m_initialized)
  22.     {
  23.         HRESULT hr = NewInit(m_iBuckets, 
  24.                              sizeof(DebuggerHashEntry), 0xffff);
  25.         if (hr != S_OK)
  26.             return (hr);
  27.  
  28.         m_initialized = true;
  29.     }
  30.  
  31.     DebuggerHashEntry *entry = (DebuggerHashEntry *) Add(HASH(pBase->GetToken()));
  32.  
  33.     if (entry == NULL)
  34.         return (E_FAIL);
  35.     else
  36.         entry->pBase = pBase;
  37.  
  38.     return (S_OK);
  39. }
  40.  
  41. DebuggerBase *DebuggerHashTable::GetBase(ULONG id)
  42. {
  43.     if (!m_initialized)
  44.         return (NULL);
  45.  
  46.     DebuggerHashEntry *entry 
  47.     = (DebuggerHashEntry *) Find(HASH(id), KEY(id)); 
  48.     if (entry == NULL)
  49.         return (NULL);
  50.     else
  51.         return (entry->pBase);
  52. }
  53.  
  54. BOOL DebuggerHashTable::RemoveBase(ULONG id)
  55. {
  56.     if (!m_initialized)
  57.         return (FALSE);
  58.  
  59.     DebuggerHashEntry *entry 
  60.     = (DebuggerHashEntry *) Find(HASH(id), KEY(id));
  61.  
  62.     if (entry == NULL)
  63.         return (FALSE);
  64.  
  65.     DebuggerBase *base = entry->pBase;
  66.  
  67.     Delete(HASH(id), (HASHENTRY *) entry);
  68.     delete base;
  69.  
  70.     return (TRUE);
  71. }
  72.  
  73. void DebuggerHashTable::RemoveAll()
  74. {
  75.     HASHFIND    find;
  76.  
  77.     for (DebuggerHashEntry *entry = (DebuggerHashEntry *) FindFirstEntry(&find);
  78.         entry != NULL;
  79.         entry = (DebuggerHashEntry *) FindNextEntry(&find))
  80.         delete entry->pBase;
  81.  
  82.     Clear();
  83. }
  84.  
  85. DebuggerBase *DebuggerHashTable::FindFirst(HASHFIND *find)
  86. {
  87.     DebuggerHashEntry *entry = (DebuggerHashEntry *) FindFirstEntry(find);
  88.     if (entry == NULL)
  89.         return (NULL);
  90.     else
  91.         return (entry->pBase);
  92. }
  93.  
  94. DebuggerBase *DebuggerHashTable::FindNext(HASHFIND *find)
  95. {
  96.     DebuggerHashEntry *entry = (DebuggerHashEntry *) FindNextEntry(find);
  97.     if (entry == NULL)
  98.         return (NULL);
  99.     else
  100.         return (entry->pBase);
  101. }
  102.  
  103. /* ------------------------------------------------------------------------- *
  104.  * DebuggerClass
  105.  * ------------------------------------------------------------------------- */
  106. DebuggerClass::DebuggerClass (ICorDebugClass *pClass)
  107.     : DebuggerBase ((ULONG)pClass),
  108.         m_szName (NULL),
  109.         m_szNamespace (NULL)
  110. {
  111. }
  112.  
  113. DebuggerClass::~DebuggerClass ()
  114. {
  115.     delete m_szName;
  116.     delete m_szNamespace;
  117. }
  118.  
  119. void DebuggerClass::SetName (WCHAR *pszName, WCHAR *pszNamespace)
  120. {
  121.     if (pszName != NULL)
  122.     {
  123.         int iLength = wcslen (pszName);
  124.         if ((m_szName = new WCHAR [iLength+1]) != NULL)
  125.             wcscpy (m_szName, pszName);
  126.     }
  127.  
  128.     if (pszNamespace != NULL)
  129.     {
  130.         int iLength = wcslen (pszNamespace);
  131.         if ((m_szNamespace = new WCHAR [iLength+1]) != NULL)
  132.             wcscpy (m_szNamespace, pszNamespace);
  133.     }
  134. }
  135.  
  136. WCHAR *DebuggerClass::GetName (void) 
  137. {
  138.     return m_szName;
  139. }
  140.  
  141. WCHAR *DebuggerClass::GetNamespace (void) 
  142. {
  143.     return m_szNamespace;
  144. }
  145.  
  146. /* ------------------------------------------------------------------------- *
  147.  * DebuggerModule
  148.  * ------------------------------------------------------------------------- */
  149.  
  150. DebuggerModule::DebuggerModule(ICorDebugModule* imodule)
  151.     : DebuggerBase((ULONG)imodule),
  152.       m_sourceFiles(11), m_functions(37), m_functionsByIF(11), m_szName(NULL),
  153.       m_loadedClasses(11), m_breakpoints(NULL), m_pISymUnmanagedReader(NULL)
  154. {
  155.     // Also initialize the source file array
  156.     for (int i=0; i<MAX_SF_BUCKETS; i++)
  157.         m_pModSourceFile [i] = NULL;
  158.     // Indicate that source file names are not yet loaded
  159.     m_fSFNamesLoaded = false;
  160.  
  161.     imodule->AddRef();
  162. }
  163.  
  164. HRESULT DebuggerModule::Init()
  165. {
  166.     // Get the necessary metadata interfaces now...
  167.     HRESULT hr = GetICorDebugModule()->GetMetaDataInterface(
  168.                                            IID_IMetaDataImport,
  169.                                            (IUnknown**)&m_pIMetaDataImport);
  170.  
  171.     if (FAILED(hr))
  172.         return hr;
  173.  
  174.     // Get the module name
  175.     WCHAR moduleName[MAX_PATH];
  176.     ULONG32 nameLen;
  177.  
  178.     hr = GetICorDebugModule()->GetName(MAX_PATH, &nameLen, moduleName);
  179.     _ASSERTE(nameLen <= MAX_PATH);
  180.  
  181.     // Don't get a reader if its a dynamic module... syms for those
  182.     // come in on update later.
  183.     BOOL isDynamic = FALSE;
  184.     hr = GetICorDebugModule()->IsDynamic(&isDynamic);
  185.     _ASSERTE(SUCCEEDED(hr));
  186.  
  187.     if (isDynamic)
  188.         return hr;
  189.     
  190.     // Get a symbol binder.
  191.     ISymUnmanagedBinder *binder;
  192.     hr = CoCreateInstance(CLSID_CorSymBinder, NULL,
  193.                           CLSCTX_INPROC_SERVER,
  194.                           IID_ISymUnmanagedBinder,
  195.                           (void**)&binder);
  196.  
  197.     if (FAILED(hr))
  198.     {
  199.         g_pShell->Write(L"Error: couldn't get a CorSymBinder for "
  200.                         L"symbol loading.\n");
  201.         return hr;
  202.     }
  203.  
  204.     // Ask the binder for a reader for this module.
  205.     hr = binder->GetReaderForFile(m_pIMetaDataImport,
  206.                                   moduleName,
  207.                                   NULL, /* no search path */
  208.                                   &m_pISymUnmanagedReader);
  209.  
  210.     // Release the binder
  211.     binder->Release();
  212.  
  213.     if (FAILED(hr))
  214.     {
  215.         g_pShell->Write(L"Warning: couldn't load symbols for %s\n",
  216.                         moduleName);
  217.         return S_OK;
  218.     }
  219.  
  220.     return hr;
  221. }
  222.  
  223. DebuggerModule::~DebuggerModule()
  224. {
  225.     while (m_breakpoints != NULL)
  226.     {
  227.         DebuggerCodeBreakpoint *bp = m_breakpoints->m_next;
  228.         delete m_breakpoints;
  229.         m_breakpoints = bp;
  230.     }
  231.  
  232.     DebuggerBreakpoint *bp = g_pShell->m_breakpoints;
  233.     while (bp != NULL)
  234.     {
  235.         if (bp->IsBoundToModule(this))
  236.             bp->RemoveBoundModule(this);
  237.  
  238.         bp = bp->m_next;
  239.     }
  240.     
  241.     GetICorDebugModule()->Release();
  242.  
  243.     if (m_pIMetaDataImport)
  244.         m_pIMetaDataImport->Release();
  245.  
  246.     if (m_pISymUnmanagedReader)
  247.         m_pISymUnmanagedReader->Release();
  248.  
  249.     // Also go through all the buckets and release the cached ModuleSourceFiles
  250.     // Need to do it only if the cache has elements in it
  251.     if (m_fSFNamesLoaded == true)
  252.     {
  253.         for (int i=0; i<MAX_SF_BUCKETS; i++)
  254.         {
  255.             ModuleSourceFile *pMod = m_pModSourceFile [i];
  256.             ModuleSourceFile *pTemp = NULL;
  257.  
  258.             while (pMod)
  259.             {
  260.                 pTemp = pMod;
  261.                 pMod = pTemp->GetNext();
  262.                 delete pTemp;            
  263.             }
  264.         }
  265.     }
  266.  
  267.     delete m_szName;
  268. }
  269.  
  270. DebuggerSourceFile *DebuggerModule::LookupSourceFile(const WCHAR *name)
  271. {
  272.     GUID g = {0};
  273.     ISymUnmanagedDocument *doc;
  274.  
  275.     if (!m_pISymUnmanagedReader)
  276.         return NULL;
  277.     
  278.     HRESULT hr = m_pISymUnmanagedReader->GetDocument((WCHAR*)name, g, g, g, &doc);
  279.  
  280.     _ASSERTE( doc != NULL );
  281.     if (FAILED(hr))
  282.         return (NULL);
  283.     else
  284.         return (ResolveSourceFile(doc));
  285. }
  286.  
  287. DebuggerSourceFile *DebuggerModule::ResolveSourceFile(ISymUnmanagedDocument *doc)
  288. {
  289.     DebuggerSourceFile *file =
  290.         (DebuggerSourceFile*)m_sourceFiles.GetBase((ULONG)doc);
  291.  
  292.     if (file == NULL)
  293.     {
  294.         file = new DebuggerSourceFile(this, doc);
  295.         _ASSERTE(file != NULL);
  296.  
  297.         if (file != NULL)
  298.             m_sourceFiles.AddBase(file);
  299.     }
  300.  
  301.     return (file);
  302. }
  303.  
  304. DebuggerFunction *DebuggerModule::ResolveFunction(mdMethodDef md,
  305.                                                   ICorDebugFunction *iFunction)
  306. {
  307.     // Make sure we don't have obviously invalid arguments
  308.     _ASSERTE((md != mdMethodDefNil) || (iFunction != NULL));
  309.  
  310.     // What will be returned
  311.     DebuggerFunction *function;
  312.  
  313.     // Get a pointer to the DebuggerFunction object
  314.     if (md != mdMethodDefNil)
  315.         function = (DebuggerFunction *)m_functions.GetBase(md);
  316.     else
  317.         function = (DebuggerFunction *)m_functionsByIF.GetBase((ULONG)iFunction);
  318.  
  319.     // Has not been created yet
  320.     if (function == NULL)
  321.     {
  322.         // Create a new object
  323.         function = new DebuggerFunction(this, md, iFunction);
  324.         _ASSERTE(function != NULL);
  325.         
  326.         // Out of memory
  327.         if (function == NULL)
  328.         {
  329.             g_pShell->ReportError(E_OUTOFMEMORY);
  330.             return NULL;
  331.         }
  332.  
  333.         // Init the DebuggerFunction object
  334.         HRESULT hr = function->Init();
  335.  
  336.         // Error check
  337.         if (FAILED(hr))
  338.         {
  339.             g_pShell->ReportError(hr);
  340.             delete function;
  341.             return NULL;
  342.         }
  343.  
  344.         // Add the DebuggerFunction object to the appropriate collection
  345.         if (md != mdMethodDefNil)
  346.             m_functions.AddBase(function);
  347.         else
  348.             m_functionsByIF.AddBase(function);
  349.     }
  350.  
  351.     // Return DebuggerFunction pointer
  352.     return (function);
  353. }
  354.  
  355. DebuggerFunction *DebuggerModule::ResolveFunction(ISymUnmanagedMethod *method,
  356.                                                   ICorDebugFunction *iFunction)
  357. {
  358.     HRESULT hr = S_OK;
  359.     
  360.     mdMethodDef tk;
  361.  
  362.     hr = method->GetToken(&tk);
  363.  
  364.     if (FAILED(hr))
  365.         return NULL;
  366.     else
  367.         return ResolveFunction(tk, iFunction);
  368. }
  369.  
  370. DebuggerModule *DebuggerModule::FromCorDebug(ICorDebugModule *module)
  371. {
  372.     // Return the DebuggerModule object
  373.     return (g_pShell->ResolveModule(module));
  374. }
  375.  
  376.  
  377. HRESULT DebuggerModule::LoadSourceFileNames (void)
  378. {
  379.     HRESULT hr = S_OK;
  380.     int        iBucket;
  381.  
  382.     // Get all of the source files within this module.
  383.     ULONG32 docCount;
  384.     ISymUnmanagedDocument **allDocs;
  385.  
  386.     if (!m_pISymUnmanagedReader)
  387.         return S_OK;
  388.  
  389.     // How many documents?
  390.     hr = m_pISymUnmanagedReader->GetDocuments(0, &docCount, NULL);
  391.  
  392.     if (FAILED(hr))
  393.         return hr;
  394.  
  395.     // Allocate space for the documents.
  396.     allDocs = (ISymUnmanagedDocument**)_alloca(docCount * sizeof(ISymUnmanagedDocument*));
  397.     _ASSERTE(allDocs != NULL);
  398.     
  399.     hr = m_pISymUnmanagedReader->GetDocuments(docCount, &docCount, allDocs);
  400.  
  401.     if (FAILED(hr))
  402.         return hr;
  403.     
  404.     // Loop over the documents, setting up each's name and path
  405.     // accordingly.
  406.     for (long i = 0; i < docCount; i++)
  407.     {
  408.         WCHAR docName[256];
  409.         ULONG32 s;
  410.  
  411.         hr = allDocs[i]->GetURL(256, &s, docName);
  412.  
  413.         if (FAILED(hr))
  414.             break;
  415.  
  416.         // @todo: the rest of the code expects an ASCII name. Fix that
  417.         // sometime soon.
  418.         MAKE_ANSIPTR_FROMWIDE(docNameA, docName);
  419.  
  420.         int iLen;
  421.         iLen = strlen(docNameA);
  422.             
  423.         if (iLen)
  424.         {
  425.             // strip the path and store just the lowercase file name
  426.             CHAR        rcFile[MAX_PATH];
  427.             _splitpath(docNameA, NULL, NULL, rcFile, NULL);
  428.  
  429.             // make the file name lowercase
  430.             int j=0;
  431.             while (rcFile [j] != '\0')
  432.             {
  433.                 rcFile[j] = tolower(rcFile[j]);
  434.                 j++;
  435.             }
  436.  
  437.             // Based on the stripped file name, decide the bucket in
  438.             // which it should go
  439.             if (rcFile [0] < 'a') 
  440.                 iBucket = 0;
  441.             else if (rcFile [0] > 'z')
  442.                 iBucket = MAX_SF_BUCKETS - 1;
  443.             else
  444.                 iBucket = (rcFile [0] - 'a') % MAX_SF_BUCKETS;
  445.  
  446.             // Allocate a new ModuleSourceFile object
  447.             ModuleSourceFile *pmsf = new ModuleSourceFile;
  448.  
  449.             if (pmsf)
  450.             {
  451.                 if (!pmsf->SetFullFileName(allDocs[i], docNameA))
  452.                 {
  453.                     hr = E_FAIL;
  454.                     break;
  455.                 }
  456.  
  457.                 // Add this ModuleSourceFile object to the cache
  458.                 pmsf->SetNext (m_pModSourceFile [iBucket]);
  459.                 m_pModSourceFile [iBucket] = pmsf;
  460.             }
  461.             else
  462.             {
  463.                 // out of memory
  464.                 hr = E_OUTOFMEMORY;
  465.                 break;
  466.             }
  467.         }
  468.  
  469.         RELEASE(allDocs[i]);
  470.     }
  471.  
  472.     // Indicate that the module's source files have been cached 
  473.     if (SUCCEEDED (hr))
  474.         m_fSFNamesLoaded = true;
  475.  
  476.     return hr;
  477. }
  478.  
  479. HRESULT    DebuggerModule::MatchStrippedFNameInModule 
  480.                                             (
  481.                                             WCHAR *pstrFileName, // file name to look for (assumed to have been converted to  lower case)
  482.                                             WCHAR **ppstrMatchedNames, // returned array containing full paths of matched filenames
  483.                                             ISymUnmanagedDocument **ppDocs, // returned aray containing documents for source file
  484.                                             int *piCount // number of files which matched the given filename
  485.                                             )
  486. {
  487.     HRESULT hr;
  488.  
  489.     *piCount = 0;
  490.     _ASSERTE (pstrFileName);
  491.  
  492.     // The filename length should be > 0 
  493.     if (!wcslen (pstrFileName))
  494.         return (E_INVALIDARG);
  495.  
  496.     if (!m_fSFNamesLoaded)
  497.     {
  498.         if ((hr = LoadSourceFileNames ()) != S_OK)
  499.             return hr;
  500.     }
  501.  
  502.     hr = E_FAIL;
  503.  
  504.     // first, extract strip the path+file name  down to just the "file.ext" name
  505.     WCHAR    rcFile[MAX_PATH];
  506.     WCHAR    rcExt[MAX_EXT];
  507.  
  508.     _wsplitpath(pstrFileName, NULL, NULL, rcFile, rcExt);
  509.     wcscat(rcFile, rcExt);
  510.  
  511.     // get the bucket in which this file should be searched for
  512.     int iBucketIndex;
  513.  
  514.     if (rcFile [0] < 'a') 
  515.         iBucketIndex = 0;
  516.     else if (rcFile [0] > 'z')
  517.         iBucketIndex = MAX_SF_BUCKETS - 1;
  518.     else
  519.         iBucketIndex = (rcFile [0] - 'a') % MAX_SF_BUCKETS;
  520.  
  521.     ModuleSourceFile *pmsf = m_pModSourceFile [iBucketIndex];
  522.  
  523.     // Search the whole list to find the files names which match
  524.     while (pmsf)
  525.     {
  526.         WCHAR    *pStrippedFileName = pmsf->GetStrippedFileName();
  527.         WCHAR    strTemp [MAX_PATH];
  528.  
  529.         // convert the name to lowercase before comparing
  530.         wcscpy (strTemp, pStrippedFileName);
  531.  
  532.         int i=0;
  533.         while (strTemp [i] != L'\0')
  534.         {
  535.             strTemp [i] = towlower (strTemp [i]);
  536.             i++;
  537.         }
  538.  
  539.         
  540.         if (!wcscmp (strTemp, rcFile))
  541.         {
  542.             _ASSERTE (*piCount < MAX_FILE_MATCHES_PER_MODULE);
  543.             // found a match
  544.             ppstrMatchedNames [*piCount] = pmsf->GetFullFileName();
  545.             ppDocs [*piCount] = pmsf->GetDocument();
  546.             (*piCount)++;
  547.             hr = S_OK;
  548.         }
  549.  
  550.         pmsf = pmsf->GetNext();
  551.     }
  552.  
  553.     return hr;
  554. }
  555.  
  556.  
  557. HRESULT        DebuggerModule::MatchFullFileNameInModule (WCHAR *pstrFileName, 
  558.                                                        ISymUnmanagedDocument **pDoc)
  559. {
  560.  
  561.     int iBucketIndex;
  562.  
  563.     HRESULT hr;
  564.  
  565.     _ASSERTE (pstrFileName);
  566.  
  567.     // The filename length should be > 0 
  568.     if (!wcslen (pstrFileName))
  569.         return (E_INVALIDARG);
  570.  
  571.     if (!m_fSFNamesLoaded)
  572.     {
  573.         if ((hr = LoadSourceFileNames ()) != S_OK)
  574.             return hr;
  575.     }
  576.  
  577.     hr = E_FAIL; // assume we won't find it in this module.
  578.  
  579.     // first, extract strip the path+file name  down to just the "file.ext" name
  580.  
  581.     WCHAR    rcFile[MAX_PATH];
  582.     WCHAR    rcExt[MAX_EXT];
  583.  
  584.     _wsplitpath(pstrFileName, NULL, NULL, rcFile, rcExt);
  585.     wcscat(rcFile, rcExt);
  586.  
  587.     // get the bucket in which this file should be searched for
  588.     if (rcFile [0] < 'a') 
  589.         iBucketIndex = 0;
  590.     else if (rcFile [0] > 'z')
  591.         iBucketIndex = MAX_SF_BUCKETS - 1;
  592.     else
  593.         iBucketIndex = (rcFile [0] - 'a') % MAX_SF_BUCKETS;
  594.  
  595.     ModuleSourceFile *pmsf = m_pModSourceFile [iBucketIndex];
  596.  
  597.     // Search the whole list to find the files name which matches
  598.     while (pmsf)
  599.     {
  600.         WCHAR    *pFullFileName = pmsf->GetFullFileName();
  601.  
  602.         if (!wcscmp (pFullFileName, pstrFileName))
  603.         {
  604.             // found a match
  605.             *pDoc = pmsf->GetDocument();
  606.             hr = S_OK;
  607.             break;
  608.         }
  609.  
  610.         pmsf = pmsf->GetNext();
  611.     }
  612.  
  613.     return hr;
  614. }
  615.  
  616.  
  617. void DebuggerModule::SetName (WCHAR *pszName)
  618. {
  619.     if (pszName != NULL)
  620.     {
  621.         m_szName = new WCHAR [wcslen (pszName) + 1];
  622.         if (m_szName != NULL)
  623.         {
  624.             wcscpy (m_szName, pszName);
  625.         }
  626.     }
  627. }
  628.  
  629. //
  630. // Update the symbols for this module. Creates the syms if they aren't
  631. // already created.
  632. //
  633. HRESULT DebuggerModule::UpdateSymbols(IStream *pStream)
  634. {
  635.     HRESULT hr = S_OK;
  636.  
  637.     // If we don't already have a reader, create one.
  638.     if (m_pISymUnmanagedReader == NULL)
  639.     {
  640.         ISymUnmanagedBinder *pBinder = NULL;
  641.         
  642.         hr = CoCreateInstance(CLSID_CorSymBinder, NULL,
  643.                               CLSCTX_INPROC_SERVER,
  644.                               IID_ISymUnmanagedBinder,
  645.                               (void**)&pBinder);
  646.  
  647.         if (SUCCEEDED(hr))
  648.         {
  649.             hr = pBinder->GetReaderFromStream(m_pIMetaDataImport,
  650.                                               pStream,
  651.                                               &m_pISymUnmanagedReader);
  652.     
  653.             if (FAILED(hr))
  654.                 m_pISymUnmanagedReader = NULL;
  655.  
  656.             pBinder->Release();
  657.         }
  658.     }
  659.     else
  660.     {
  661.         // We already have a reader, so just replace the symbols. We
  662.         // replace instead of update because we are doing this only
  663.         // for dynamic modules and the syms are cumulative.
  664.         hr = m_pISymUnmanagedReader->ReplaceSymbolStore(NULL, pStream);
  665.     }
  666.     
  667.     return hr;
  668. }
  669.  
  670. void DebuggerShell::PrintGlobalVariable (mdFieldDef mdTok, 
  671.                                          WCHAR  *wszName,
  672.                                          DebuggerModule *dm)
  673. {
  674.     ICorDebugModule *mod = dm->GetICorDebugModule();
  675.     ICorDebugValue *val = NULL;
  676.     HRESULT hr = S_OK;
  677.  
  678.     _ASSERTE( mod != NULL );
  679.     
  680.     hr = mod->GetGlobalVariableValue(mdTok, &val);
  681.     if (FAILED(hr))
  682.         return;
  683.  
  684.     this->PrintVariable(wszName,
  685.                         val,
  686.                         4, //sure, sounds good
  687.                         TRUE);
  688.  
  689.     RELEASE(val);
  690.  
  691.     Write(L"\n");
  692. }
  693.  
  694. #define PRINT_ALL        1
  695. #define MATCH_N_CHARS    2
  696. #define MATCH_ALL_CHARS    3
  697.  
  698. BOOL DebuggerModule::PrintGlobalVariables (WCHAR *szSearchString, 
  699.                                            char *szModName,
  700.                                            DebuggerModule *dm)
  701. {
  702.     BOOL fWildCard = FALSE;
  703.     int iMatchKind;
  704.     int iLength = wcslen (szSearchString);
  705.     char szSearchName [MAX_SYMBOL_NAME_LENGTH];
  706.  
  707.     BOOL fDone = FALSE;
  708.     for (int i=0; i<iLength; i++)
  709.     {
  710.         if (szSearchString [i] == L'*')
  711.         {
  712.             fWildCard = TRUE;
  713.             iLength = i;
  714.             break;
  715.         }
  716.     }
  717.  
  718.     if (iLength==0)
  719.     {
  720.         // print all symbols
  721.         iMatchKind = PRINT_ALL;
  722.     }
  723.     else
  724.     {
  725.         szSearchString [iLength] = L'\0';
  726.         MAKE_UTF8PTR_FROMWIDE (szSearchName1, szSearchString);
  727.  
  728.         strcpy (szSearchName, szSearchName1);
  729.  
  730.         if (fWildCard)
  731.         {
  732.             // match 'iLength' characters only
  733.             iMatchKind = MATCH_N_CHARS;
  734.         }
  735.         else
  736.         {
  737.             // match the whole string
  738.             iMatchKind = MATCH_ALL_CHARS;
  739.         }
  740.     }
  741.  
  742.     // first, look for the global functions
  743.     HCORENUM phEnum = 0;
  744.     mdMethodDef rTokens[100];
  745.     unsigned long count;
  746.     HRESULT hr;
  747.     MDUTF8CSTR name;
  748.     MDUTF8STR  u_name;
  749.     MDUTF8STR  szMDName;
  750.     bool anythingPrinted = false;
  751.  
  752.     u_name = new char[256];
  753.  
  754.     do 
  755.     {
  756.         hr = m_pIMetaDataImport->EnumFields(&phEnum, NULL, &rTokens[0], 100, &count);
  757.  
  758.         if (!SUCCEEDED(hr))
  759.         {
  760.             g_pShell->ReportError(hr);
  761.             goto ErrExit;
  762.         }
  763.  
  764.         for (i = 0; i < count; i++)
  765.         {
  766.             hr = m_pIMetaDataImport->GetNameFromToken(rTokens[i], &name);
  767.  
  768.             if (name == NULL)
  769.                 continue;
  770.  
  771.             MAKE_WIDEPTR_FROMUTF8( wszName, name );
  772.  
  773.             szMDName = (MDUTF8STR) name;
  774.  
  775.             if (iMatchKind == PRINT_ALL)
  776.             {
  777.                 g_pShell->PrintGlobalVariable (rTokens[i], 
  778.                                                wszName,
  779.                                                dm);
  780.                 anythingPrinted = true;
  781.             }
  782.             else
  783.             {
  784.                 if (iMatchKind == MATCH_N_CHARS)
  785.                 {
  786.                     if (!strncmp (szMDName, szSearchName, iLength))
  787.                     {
  788.                         g_pShell->PrintGlobalVariable (rTokens[i], 
  789.                                                        wszName,
  790.                                                        dm);
  791.                         anythingPrinted = true;
  792.                     }
  793.                 }
  794.                 else
  795.                 {
  796.                     if (!strcmp (szMDName, szSearchName))
  797.                     {
  798.                         g_pShell->PrintGlobalVariable (rTokens[i], 
  799.                                                        wszName,
  800.                                                        dm);
  801.                         anythingPrinted = true;
  802.                     }
  803.                 }
  804.             }
  805.         }
  806.     }
  807.     while (count > 0); 
  808.  
  809. ErrExit:    
  810.     delete u_name;
  811.  
  812.     if (!anythingPrinted)
  813.         return FALSE;
  814.     return TRUE;
  815. }
  816.  
  817. BOOL DebuggerModule::PrintMatchingSymbols (WCHAR *szSearchString, char *szModName)
  818. {
  819.     BOOL fWildCard = FALSE;
  820.     int iMatchKind;
  821.     int iLength = wcslen (szSearchString);
  822.     char szSearchName [MAX_SYMBOL_NAME_LENGTH];
  823.  
  824.     BOOL fDone = FALSE;
  825.     for (int i=0; i<iLength; i++)
  826.     {
  827.         if (szSearchString [i] == L'*')
  828.         {
  829.             fWildCard = TRUE;
  830.             iLength = i;
  831.             break;
  832.         }
  833.     }
  834.  
  835.     if (iLength==0)
  836.     {
  837.         // print all symbols
  838.         iMatchKind = PRINT_ALL;
  839.     }
  840.     else
  841.     {
  842.         szSearchString [iLength] = L'\0';
  843.         MAKE_UTF8PTR_FROMWIDE (szSearchName1, szSearchString);
  844.  
  845.         strcpy (szSearchName, szSearchName1);
  846.  
  847.         if (fWildCard)
  848.         {
  849.             // match 'iLength' characters only
  850.             iMatchKind = MATCH_N_CHARS;
  851.         }
  852.         else
  853.         {
  854.             // match the whole string
  855.             iMatchKind = MATCH_ALL_CHARS;
  856.         }
  857.     }
  858.  
  859.     // first, look for the global functions
  860.     HCORENUM phEnum = 0;
  861.     mdMethodDef rTokens[100];
  862.     mdTypeDef rClassTokens [100];
  863.     unsigned long count;
  864.     HRESULT hr;
  865.     MDUTF8CSTR name;
  866.     MDUTF8CSTR name1;
  867.     MDUTF8STR  u_name;
  868.     MDUTF8STR  szMDName;
  869.     bool anythingPrinted = false;
  870.  
  871.     u_name = new char[256];
  872.  
  873.     do 
  874.     {
  875.         hr = m_pIMetaDataImport->EnumMethods(&phEnum, NULL, &rTokens[0], 100, &count);
  876.  
  877.         if (!SUCCEEDED(hr))
  878.         {
  879.             g_pShell->ReportError(hr);
  880.             goto ErrExit;
  881.         }
  882.  
  883.         for (i = 0; i < count; i++)
  884.         {
  885.             hr = m_pIMetaDataImport->GetNameFromToken(rTokens[i], &name);
  886.  
  887.             if (name == NULL)
  888.                 continue;
  889.  
  890.             szMDName = (MDUTF8STR) name;
  891.  
  892.             if (iMatchKind == PRINT_ALL)
  893.             {
  894.                 g_pShell->Write (L"%S!::%S\n", szModName, szMDName);
  895.                 anythingPrinted = true;
  896.             }
  897.             else
  898.             {
  899.                 if (iMatchKind == MATCH_N_CHARS)
  900.                 {
  901.                     if (!strncmp (szMDName, szSearchName, iLength))
  902.                     {
  903.                         g_pShell->Write (L"%S!::%S\n", szModName, szMDName);
  904.                         anythingPrinted = true;
  905.                     }
  906.                 }
  907.                 else
  908.                 {
  909.                     if (!strcmp (szMDName, szSearchName))
  910.                     {
  911.                         g_pShell->Write (L"%S!::%S\n", szModName, szMDName);
  912.                         anythingPrinted = true;
  913.                     }
  914.                 }
  915.             }
  916.         }
  917.     }
  918.     while (count > 0); 
  919.  
  920.     // now enumerate all the classes...
  921.     phEnum = 0;
  922.     do
  923.     {
  924.         hr = m_pIMetaDataImport->EnumTypeDefs (&phEnum, &rClassTokens[0], 100, &count);
  925.  
  926.         if (!SUCCEEDED(hr))
  927.         {
  928.             g_pShell->ReportError(hr);
  929.             goto ErrExit;
  930.         }
  931.  
  932.         for (i = 0; i < count; i++)
  933.         {
  934.             BOOL fMatchFound = FALSE;
  935.             WCHAR wszClassName [MAX_SYMBOL_NAME_LENGTH];
  936.             ULONG ulClassNameLen;
  937.             CLASSVERSION version;
  938.             DWORD dwTypeDefFlags;
  939.             mdToken tkExtends;
  940.  
  941.             wszClassName [0] = L'\0';
  942.  
  943.             hr = m_pIMetaDataImport->GetTypeDefProps (rClassTokens [i],
  944.                                                       wszClassName,
  945.                                                       MAX_SYMBOL_NAME_LENGTH-1,
  946.                                                       &ulClassNameLen,
  947.                                                       &version,
  948.                                                       &dwTypeDefFlags,
  949.                                                       &tkExtends);                                                        
  950.  
  951.             if (wcslen (wszClassName) == 0)
  952.                 continue;
  953.  
  954.             MAKE_ANSIPTR_FROMWIDE (szMDClassName, wszClassName);
  955.  
  956.             if (iMatchKind == PRINT_ALL)
  957.             {
  958.                 fMatchFound = TRUE;
  959.             }
  960.             else
  961.             {
  962.                 if (iMatchKind == MATCH_N_CHARS)
  963.                 {
  964.                     if (!strncmp (szMDClassName, szSearchName, iLength))
  965.                     {
  966.                         fMatchFound = TRUE;
  967.                     }
  968.                 }
  969.                 else
  970.                 {
  971.                     if (!strcmp (szMDClassName, szSearchName))
  972.                     {
  973.                         fMatchFound = TRUE;
  974.                     }
  975.                 }
  976.             }
  977.  
  978.  
  979.             if (fMatchFound)
  980.             {
  981.                 ULONG ulClassCount;
  982.                 HCORENUM phClassEnum = 0;
  983.                 do
  984.                 {
  985.                     ulClassCount = 0;
  986.                     hr = m_pIMetaDataImport->EnumMethods(&phClassEnum, rClassTokens [i], &rTokens[0], 100, &ulClassCount);
  987.  
  988.                     if (!SUCCEEDED(hr))
  989.                     {
  990.                         g_pShell->ReportError(hr);
  991.                         goto ErrExit;
  992.                     }
  993.  
  994.                     for (int j = 0; j < ulClassCount; j++)
  995.                     {
  996.                         name1 = NULL;
  997.                         hr = m_pIMetaDataImport->GetNameFromToken(rTokens[j], &name1);
  998.  
  999.                         if (name1 == NULL)
  1000.                             continue;
  1001.  
  1002.                         szMDName = (MDUTF8STR)name1;
  1003.  
  1004.                         g_pShell->Write (L"%S!%S::%S\n", szModName, szMDClassName, szMDName);
  1005.                         anythingPrinted = true;
  1006.                     }
  1007.                 }
  1008.                 while (ulClassCount > 0);
  1009.             }
  1010.         }
  1011.  
  1012.     }while (count > 0);
  1013.  
  1014. ErrExit:    
  1015.     delete u_name;
  1016.  
  1017.     if (!anythingPrinted)
  1018.         return FALSE;
  1019.     return TRUE;
  1020. }
  1021.  
  1022.  
  1023. /* ------------------------------------------------------------------------- *
  1024.  * DebuggerSourceFile
  1025.  * ------------------------------------------------------------------------- */
  1026.  
  1027. DebuggerSourceFile::DebuggerSourceFile(DebuggerModule *module,
  1028.                                        ISymUnmanagedDocument *doc)
  1029.     : DebuggerBase((LONG)doc), m_module(module), 
  1030.       m_allBlocksLoaded(false), 
  1031.       m_totalLines(0), m_lineStarts(NULL), 
  1032.       m_source(NULL), m_sourceTextLoaded(false), 
  1033.       m_name(NULL), m_path(NULL),
  1034.       m_sourceNotFound(FALSE)
  1035. {
  1036.     ULONG32 nameLen;
  1037.  
  1038.     // Get the length of the name first
  1039.     HRESULT hr = doc->GetURL(0, &nameLen, NULL);
  1040.  
  1041.     // Allocate space for the name
  1042.     m_name = new WCHAR[nameLen + 1];
  1043.  
  1044.     if (m_name)
  1045.     {
  1046.         // Now, copy the name for real.
  1047.         hr = doc->GetURL(nameLen + 1, &nameLen, m_name);
  1048.     }
  1049.     else
  1050.         hr = E_OUTOFMEMORY;
  1051.     
  1052.     // If unsuccessful, don't initialize the source name
  1053.     if (FAILED(hr))
  1054.     {
  1055.         g_pShell->ReportError(hr);
  1056.  
  1057.         if (m_name)
  1058.             delete [] m_name;
  1059.         
  1060.         m_name = NULL;
  1061.     }
  1062. }
  1063.  
  1064. DebuggerSourceFile::~DebuggerSourceFile()
  1065. {
  1066.     delete [] m_source;
  1067.     delete [] m_lineStarts;
  1068.     delete [] m_path;
  1069.     delete [] m_name;
  1070. }
  1071.  
  1072. // LoadText loads the text of a source file and builds a table of pointers
  1073. // to the start of each line.
  1074. //
  1075. // @todo: will probally want to return extended error information one day
  1076. // instead of just true or false.
  1077. //
  1078. BOOL DebuggerSourceFile::LoadText(const WCHAR* path, bool bChangeOfName)
  1079. {
  1080.     BOOLEAN fRetVal = FALSE;
  1081.     char *sourceA = NULL;
  1082.     int size = 0;
  1083.     WCHAR* ptr = NULL;
  1084.     unsigned int i = 0;
  1085.     int ilen = 0;
  1086.     
  1087.     if (m_sourceTextLoaded)
  1088.         return (TRUE);
  1089.  
  1090.     // Where to store fully qualified name
  1091.     char fullyQualifiedName[MAX_PATH];
  1092.  
  1093.     // Must convert to ANSI for Win9x users
  1094.     MAKE_ANSIPTR_FROMWIDE(pathA, path);
  1095.     _ASSERTE(pathA != NULL);
  1096.  
  1097.  
  1098.     HRESULT hr;
  1099.  
  1100.     // Let the shell see if it can resolve the source location.
  1101.     if ((hr = g_pShell->ResolveSourceFile(this, pathA, fullyQualifiedName, MAX_PATH, bChangeOfName)) != S_OK)
  1102.     {
  1103.         if (!m_sourceNotFound)
  1104.         {
  1105.             g_pShell->Write(L"\nError loading source file '%s': File not found\n", m_name);
  1106.             m_sourceNotFound = TRUE;
  1107.         }
  1108.  
  1109.         return (FALSE);
  1110.  
  1111.     }
  1112.     
  1113.     
  1114.     m_sourceNotFound = FALSE;
  1115.  
  1116.     // Read the source file into memory.
  1117.     HANDLE hFile = CreateFileA(fullyQualifiedName, GENERIC_READ,
  1118.                                FILE_SHARE_READ, NULL, OPEN_EXISTING,
  1119.                                FILE_ATTRIBUTE_NORMAL, NULL);
  1120.  
  1121.     if (hFile == INVALID_HANDLE_VALUE)
  1122.     {
  1123.         HRESULT hr = HRESULT_FROM_WIN32(GetLastError());
  1124.  
  1125.         // No luck, report error.
  1126.         g_pShell->ReportError(hr);
  1127.         return (FALSE);
  1128.     }
  1129.  
  1130.     DWORD sizeA = GetFileSize(hFile, NULL);
  1131.  
  1132.     if (sizeA == 0xFFFFFFFF)
  1133.     {
  1134.         g_pShell->ReportError(HRESULT_FROM_WIN32(GetLastError()));
  1135.         CloseHandle(hFile);
  1136.         return (FALSE);
  1137.     }
  1138.  
  1139.     sourceA = new char[ (sizeA * sizeof(char)) ];
  1140.     if (sourceA == NULL)
  1141.     {
  1142.         g_pShell->Write( L"Insufficient memory to load file '%s'\n",m_name );
  1143.         CloseHandle(hFile);
  1144.         return (FALSE);
  1145.     }
  1146.  
  1147.     DWORD sizeReadA;
  1148.     BOOL ret = ReadFile(hFile, (void*) sourceA, sizeA, &sizeReadA, NULL);
  1149.  
  1150.     CloseHandle(hFile);
  1151.  
  1152.     if ((ret == FALSE) || (sizeA != sizeReadA))
  1153.     {
  1154.         if (ret == FALSE)
  1155.             g_pShell->ReportError(HRESULT_FROM_WIN32(GetLastError()));
  1156.  
  1157.         goto LExit;
  1158.     }
  1159.  
  1160.     // Translate the source file into UNICODE
  1161.     size = MultiByteToWideChar(CP_ACP, 0, sourceA, sizeA, NULL, 0);
  1162.  
  1163.     m_source = new WCHAR[size+1];
  1164.     _ASSERTE(m_source != NULL);
  1165.  
  1166.     if (m_source == NULL)
  1167.         goto LExit;
  1168.  
  1169.     MultiByteToWideChar(CP_ACP, 0, sourceA, sizeA, m_source, size);
  1170.  
  1171.     // Null terminate the wide string array
  1172.     m_source [size] = L'\0';
  1173.  
  1174.     //
  1175.     // Figure out how many lines are in this file.
  1176.     //
  1177.     ptr = m_source;
  1178.     m_totalLines = 0;
  1179.  
  1180.     while (ptr < (m_source + size))
  1181.     {
  1182.         if (*ptr++ == L'\n')
  1183.             m_totalLines++;
  1184.     }
  1185.  
  1186.     // account for the fact that the last line of the 
  1187.     // file may contain text. So number of lines needs 
  1188.     // to be incremented if this is the case.
  1189.     if ((size > 0) && (*(ptr-1) != L'\n'))
  1190.         m_totalLines++;
  1191.  
  1192.     // Build an array to point to the beginning of each line of the file.
  1193.     // Chop up the file into separate strings while we're at it.
  1194.     if (m_totalLines == 0)
  1195.         goto LExit;
  1196.  
  1197.  
  1198.     m_lineStarts = new WCHAR*[m_totalLines];
  1199.     _ASSERTE(m_lineStarts != NULL);
  1200.  
  1201.     if (m_lineStarts == NULL)
  1202.     {
  1203.         delete m_source;
  1204.         goto LExit;
  1205.     }
  1206.  
  1207.     ptr = m_source;
  1208.     m_lineStarts[i++] = ptr;
  1209.  
  1210.     while (ptr < (m_source + size))
  1211.     {
  1212.         if (*ptr++ == '\n')
  1213.         {
  1214.             *(ptr - 1) = '\0';
  1215.  
  1216.             if ((ptr > m_source + 1) && (*(ptr - 2) == '\r'))
  1217.                 *(ptr - 2) = '\0';
  1218.  
  1219.             if (i < m_totalLines)
  1220.                 m_lineStarts[i++] = ptr;
  1221.         }
  1222.     }
  1223.  
  1224.     m_sourceTextLoaded = TRUE;
  1225.  
  1226.     ilen = MultiByteToWideChar(CP_ACP, 0, fullyQualifiedName, -1, NULL, 0);
  1227.     m_path = new WCHAR[ilen+1];
  1228.     if (m_path)
  1229.         MultiByteToWideChar(CP_ACP, 0, fullyQualifiedName, -1, m_path, ilen+1);
  1230.     fRetVal =  (TRUE);
  1231.  LExit:
  1232.     if (sourceA != NULL )
  1233.     {
  1234.         delete [] sourceA;
  1235.         sourceA = NULL;
  1236.     }
  1237.     
  1238.     return fRetVal;
  1239. }
  1240.  
  1241. BOOL DebuggerSourceFile::ReloadText(const WCHAR *path, bool bChangeOfName)
  1242. {
  1243.     m_sourceTextLoaded = FALSE;
  1244.  
  1245.     if (m_source != NULL)
  1246.     {
  1247.         delete m_source;
  1248.         m_source = NULL;
  1249.     }
  1250.  
  1251.     if (m_lineStarts != NULL)
  1252.     {
  1253.         delete m_lineStarts;
  1254.         m_lineStarts = NULL;
  1255.     }
  1256.  
  1257.     m_totalLines = 0;
  1258.  
  1259.     return (LoadText(path, bChangeOfName));
  1260. }
  1261.  
  1262. unsigned int DebuggerSourceFile::FindClosestLine(unsigned int line,
  1263.                                                  bool silently)
  1264. {
  1265.     HRESULT hr = S_OK;
  1266.  
  1267.     // Find and return the closest line in this document.
  1268.     ULONG32 closeLine;
  1269.     hr = GetDocument()->FindClosestLine(line, &closeLine);
  1270.  
  1271.     if (SUCCEEDED(hr))
  1272.     {
  1273.         // @TODO: This is a symbolstore failure.  Bug 28393.
  1274.         if ((hr == S_FALSE) ||
  1275.             ((closeLine > (line + 3)) || (closeLine < (line - 3))))
  1276.             hr = E_FAIL;
  1277.     }
  1278.  
  1279.     if (SUCCEEDED(hr))
  1280.         return closeLine;
  1281.     else
  1282.     {
  1283.         if (!silently)
  1284.             g_pShell->Write(L"Warning: source line may not have code. "
  1285.                             L"Breakpoint binding may fail.\n");
  1286.  
  1287.         return line;
  1288.     }
  1289. }
  1290.  
  1291. /* ------------------------------------------------------------------------- *
  1292.  * DebuggerFunction
  1293.  * ------------------------------------------------------------------------- */
  1294.  
  1295. //
  1296. // _skipTypeInSignature -- skip past a type in a given signature.
  1297. // Returns the number of bytes used by the type in the signature.
  1298. //
  1299. static ULONG _skipTypeInSignature(PCCOR_SIGNATURE sig)
  1300. {
  1301.     ULONG cb = 0;
  1302.     ULONG elementType;
  1303.  
  1304.     cb += CorSigUncompressData(&sig[cb], &elementType);
  1305.  
  1306.     if ((elementType == ELEMENT_TYPE_CLASS) ||
  1307.         (elementType == ELEMENT_TYPE_VALUECLASS))
  1308.     {
  1309.         // Skip over typeref.
  1310.         mdToken typeRef;
  1311.         cb += CorSigUncompressToken(&sig[cb], &typeRef);
  1312.     }
  1313.     else if ((elementType == ELEMENT_TYPE_PTR) ||
  1314.              (elementType == ELEMENT_TYPE_BYREF) ||
  1315.              (elementType == ELEMENT_TYPE_GENERICARRAY) ||
  1316.              (elementType == ELEMENT_TYPE_PINNED) ||
  1317.              (elementType == ELEMENT_TYPE_SZARRAY))
  1318.     {
  1319.         // Skip over extra embedded type.
  1320.         cb += _skipTypeInSignature(&sig[cb]);
  1321.     }
  1322.     else if ((elementType == ELEMENT_TYPE_ARRAY) ||
  1323.              (elementType == ELEMENT_TYPE_ARRAY))
  1324.     {
  1325.         // Skip over extra embedded type.
  1326.         cb += _skipTypeInSignature(&sig[cb]);
  1327.  
  1328.         // Skip over rank
  1329.         ULONG rank;
  1330.         cb += CorSigUncompressData(&sig[cb], &rank);
  1331.  
  1332.         if (rank > 0)
  1333.         {
  1334.             // how many sizes?
  1335.             ULONG sizes;
  1336.             cb += CorSigUncompressData(&sig[cb], &sizes);
  1337.  
  1338.             // read out all the sizes
  1339.             unsigned int i;
  1340.  
  1341.             for (i = 0; i < sizes; i++)
  1342.             {
  1343.                 ULONG dimSize;
  1344.                 cb += CorSigUncompressData(&sig[cb], &dimSize);
  1345.             }
  1346.  
  1347.             // how many lower bounds?
  1348.             ULONG lowers;
  1349.             cb += CorSigUncompressData(&sig[cb], &lowers);
  1350.  
  1351.             // read out all the lower bounds.
  1352.             for (i = 0; i < lowers; i++)
  1353.             {
  1354.                 int lowerBound;
  1355.                 cb += CorSigUncompressSignedInt(&sig[cb], &lowerBound);
  1356.             }
  1357.         }
  1358.     }
  1359.  
  1360.     return (cb);
  1361. }
  1362.  
  1363. //
  1364. // Static, global byte used to represent a signature for a class. A pointer
  1365. // to this is used as the signature for the "this" argument to methods
  1366. //
  1367. static const BYTE g_ObjectSignature = ELEMENT_TYPE_CLASS;
  1368.  
  1369. //
  1370. // DebuggerFunction
  1371. //
  1372. // @todo VC_HACK: the extra hash and the work to notice if the method def
  1373. // token is nil is to support debugging VC_HACK programs.
  1374. //
  1375. DebuggerFunction::DebuggerFunction(DebuggerModule *m, mdMethodDef md,
  1376.                                    ICorDebugFunction *iFunction)
  1377.     : DebuggerBase(md), m_module(m), m_class(0), m_ifunction(iFunction), 
  1378.       m_isStatic(false),  m_allBlocksLoaded(false), m_allScopesLoaded(false),
  1379.       m_arguments(NULL), m_argCount(0), m_VCHack(FALSE),
  1380.       m_returnType(NULL), m_signature(NULL), m_name(NULL), m_className(NULL),
  1381.       m_namespaceName(NULL),
  1382.       m_ilCode(NULL), m_ilCodeSize(0), m_nativeCode(NULL), m_nativeCodeSize(0),
  1383.       m_symMethod(NULL), m_SPCount(0), m_SPOffsets(NULL), m_SPDocuments(NULL),
  1384.       m_SPLines(NULL)
  1385. {
  1386.     if (md == mdMethodDefNil)
  1387.     {
  1388.         m_token = (ULONG) iFunction;
  1389.         iFunction->AddRef();
  1390.         m_VCHack = TRUE;
  1391.     }
  1392. }
  1393.  
  1394.  
  1395. //
  1396. // Obtain & Cache sequence point information
  1397. //
  1398. HRESULT DebuggerFunction::CacheSequencePoints(void)
  1399. {
  1400.     HRESULT hr = S_OK;
  1401.     
  1402.     if (m_SPCount)
  1403.     {
  1404.         if (m_SPOffsets != NULL)
  1405.         {
  1406.             delete [] m_SPOffsets;
  1407.         }
  1408.         if (m_SPDocuments != NULL)
  1409.         {
  1410.             delete [] m_SPDocuments;
  1411.         }
  1412.         if (m_SPLines != NULL)
  1413.         {
  1414.             delete [] m_SPLines;
  1415.         }
  1416.     }
  1417.     
  1418.     // Now, load up the sequence points for this function since we
  1419.     // know that we'll need them later.
  1420.     if (m_symMethod)
  1421.     {
  1422.         hr = m_symMethod->GetSequencePointCount(&m_SPCount);
  1423.  
  1424.         TESTANDRETURNHR(hr);
  1425.  
  1426.         if (m_SPCount)
  1427.         {
  1428.             m_SPOffsets = new ULONG32[m_SPCount];
  1429.  
  1430.             if (!m_SPOffsets)
  1431.                 return E_OUTOFMEMORY;
  1432.     
  1433.             m_SPDocuments = new ISymUnmanagedDocument*[m_SPCount];
  1434.  
  1435.             if (!m_SPDocuments)
  1436.                 return E_OUTOFMEMORY;
  1437.     
  1438.             m_SPLines = new ULONG32[m_SPCount];
  1439.  
  1440.             if (!m_SPCount)
  1441.                 return E_OUTOFMEMORY;
  1442.  
  1443.             ULONG32 actualCount;
  1444.         
  1445.             hr = m_symMethod->GetSequencePoints(m_SPCount,
  1446.                                                 &actualCount,
  1447.                                                 m_SPOffsets,
  1448.                                                 m_SPDocuments,
  1449.                                                 m_SPLines,
  1450.                                                 NULL,
  1451.                                                 NULL,
  1452.                                                 NULL);
  1453.  
  1454.             TESTANDRETURNHR(hr);
  1455.  
  1456.             _ASSERTE(actualCount == m_SPCount);
  1457.         }
  1458.     }
  1459.     
  1460.     return hr;
  1461. }
  1462.  
  1463. //
  1464. // Initialize a DebuggerFunction object.
  1465. //
  1466. HRESULT DebuggerFunction::Init(void)
  1467. {
  1468.     if (m_VCHack)
  1469.         return (S_OK);
  1470.  
  1471.     HRESULT hr = S_OK;
  1472.     
  1473.     m_nEditAndContinueLastSynched = g_pShell->m_cEditAndContinues;
  1474.  
  1475.     // Get the symbol reader method for this method.
  1476.     if (GetModule()->GetSymbolReader() != NULL)
  1477.     {
  1478.         hr = GetModule()->GetSymbolReader()->GetMethod(GetToken(), &m_symMethod);
  1479.  
  1480.         if (hr != S_OK)
  1481.             m_symMethod = NULL;
  1482.     }
  1483.     else
  1484.         m_symMethod = NULL;
  1485.  
  1486.     CacheSequencePoints();
  1487.  
  1488.     //
  1489.     // Get properties of the method.
  1490.     //
  1491.     mdTypeDef   classToken = mdTypeDefNil;
  1492.     WCHAR       methodName[BUF_SIZE];
  1493.     ULONG       methodNameLength = 0;
  1494.     PCCOR_SIGNATURE sigBlob = NULL;
  1495.     ULONG       sigBlobSize = 0;
  1496.     DWORD       methodAttr = 0;
  1497.     ULONG       cb = 0;
  1498.  
  1499.     hr = m_module->GetMetaData()->GetMethodProps(GetToken(),
  1500.                                                  &classToken,
  1501.                                                  methodName, 256,
  1502.                                                  &methodNameLength,
  1503.                                                  &methodAttr,
  1504.                                                  &sigBlob,
  1505.                                                  &sigBlobSize,
  1506.                                                  NULL, NULL);
  1507.  
  1508.     TESTANDRETURNHR(hr);
  1509.  
  1510.     m_signature = sigBlob; //@todo - do we have to release this, or is
  1511.                            // this a pointer into MD owned space?
  1512.     m_class = classToken;
  1513.     m_name = new WCHAR[methodNameLength];
  1514.     _ASSERTE(m_name != NULL);
  1515.  
  1516.     if (m_name == NULL)
  1517.         return (E_OUTOFMEMORY);
  1518.  
  1519.     memcpy(m_name, methodName, methodNameLength * sizeof(WCHAR));
  1520.  
  1521.     //
  1522.     // Get properites of this method's class. (Mostly for the class name.)
  1523.     //
  1524.     if (m_class != mdTypeDefNil)
  1525.     {
  1526.         WCHAR       fullName[MAX_CLASS_NAME];
  1527.         ULONG       fullNameSize = 0;
  1528.         WCHAR       *Namespace;
  1529.         ULONG       NamespaceSize=0;
  1530.         WCHAR       *className;
  1531.         ULONG       classNameSize = 0;
  1532.  
  1533.         hr = m_module->GetMetaData()->GetTypeDefProps(classToken,
  1534.                                                       fullName, MAX_CLASS_NAME,
  1535.                                                       &fullNameSize,
  1536.                                                       NULL, NULL,
  1537.                                                       NULL);
  1538.         TESTANDRETURNHR(hr);
  1539.  
  1540.         Namespace = fullName;
  1541.         className  = wcsrchr(fullName, L'.');
  1542.         if (className)
  1543.             *className++ = 0;
  1544.         else
  1545.         {
  1546.             Namespace = L"";
  1547.             className = fullName;
  1548.         }
  1549.  
  1550.         NamespaceSize = wcslen(Namespace) + 1;
  1551.         classNameSize = wcslen(className) + 1;
  1552.  
  1553.         m_namespaceName = new WCHAR[NamespaceSize+1];
  1554.         _ASSERTE(m_namespaceName != NULL);
  1555.  
  1556.         if (m_namespaceName == NULL)
  1557.             return (E_OUTOFMEMORY);
  1558.  
  1559.         memcpy(m_namespaceName, Namespace, NamespaceSize * sizeof(WCHAR));
  1560.  
  1561.         if (wcslen(Namespace))
  1562.             wcscat (m_namespaceName, L".");
  1563.         else
  1564.             m_namespaceName[0] = L'\0';
  1565.  
  1566.  
  1567.         m_className = new WCHAR[classNameSize];
  1568.         _ASSERTE(m_className != NULL);
  1569.  
  1570.         if (m_className == NULL)
  1571.             return (E_OUTOFMEMORY);
  1572.  
  1573.         memcpy(m_className, className, classNameSize * sizeof(WCHAR));    
  1574.     }
  1575.     else
  1576.     {
  1577.         m_className = new WCHAR[1];
  1578.         _ASSERTE(m_className != NULL);
  1579.         
  1580.         if (m_className == NULL)
  1581.             return (E_OUTOFMEMORY);
  1582.         m_className [0] = L'\0';
  1583.  
  1584.         m_namespaceName = new WCHAR[1];
  1585.         _ASSERTE(m_namespaceName != NULL);
  1586.         
  1587.         if (m_namespaceName == NULL)
  1588.             return (E_OUTOFMEMORY);
  1589.         m_namespaceName [0] = L'\0';
  1590.     }
  1591.  
  1592.     //
  1593.     // Make sure we have a method signature.
  1594.     //
  1595.     ULONG callConv;
  1596.     cb += CorSigUncompressData(&sigBlob[cb], &callConv);
  1597.     _ASSERTE(callConv != IMAGE_CEE_CS_CALLCONV_FIELD);
  1598.  
  1599.     //
  1600.     // Grab the argument count.
  1601.     //
  1602.     ULONG argCount;
  1603.     cb += CorSigUncompressData(&sigBlob[cb], &argCount);
  1604.     m_argCount = argCount;
  1605.  
  1606.     //
  1607.     // Have the return type point directly to the return type in the
  1608.     // method signature.
  1609.     //
  1610.     m_returnType = &sigBlob[cb];
  1611.  
  1612.     //
  1613.     // Skip past the return type.
  1614.     //
  1615.     cb += _skipTypeInSignature(&sigBlob[cb]);
  1616.  
  1617.     m_isStatic = (methodAttr & mdStatic) != 0;
  1618.  
  1619.     unsigned int i;
  1620.  
  1621.     if (!m_isStatic)
  1622.         m_argCount++;
  1623.  
  1624.     if (m_argCount)
  1625.     {
  1626.         m_arguments = new DebuggerVarInfo[m_argCount];
  1627.  
  1628.         if (m_arguments == NULL)
  1629.         {
  1630.             m_argCount = 0;
  1631.             return (S_OK);
  1632.         }
  1633.  
  1634.         if (!m_isStatic)
  1635.         {
  1636.             char *newName = new char[5];
  1637.             _ASSERTE(newName != NULL);
  1638.             strcpy(newName, "this");
  1639.             m_arguments[0].name = newName;
  1640.             m_arguments[0].sig = (PCCOR_SIGNATURE) &g_ObjectSignature; // never really used...
  1641.             m_arguments[0].varNumber = 0;
  1642.  
  1643.             i = 1;
  1644.         }
  1645.         else
  1646.             i = 0;
  1647.  
  1648.         for (; i < m_argCount; i++)
  1649.         {
  1650.             m_arguments[i].name = NULL;
  1651.             m_arguments[i].sig = &sigBlob[cb];
  1652.             m_arguments[i].varNumber = i;
  1653.  
  1654.             cb += _skipTypeInSignature(&sigBlob[cb]);
  1655.         }
  1656.     }
  1657.  
  1658.     hr = m_module->GetICorDebugModule()->GetFunctionFromToken(GetToken(),
  1659.                                                               &m_ifunction);
  1660.  
  1661.     if( FAILED(hr) )
  1662.         return hr;
  1663.  
  1664.     // Now, load any argument names.
  1665.     if (m_argCount > 0)
  1666.     {
  1667.         HCORENUM paramEnum = NULL;
  1668.         bool fCloseEnum = false;
  1669.         IMetaDataImport *pIMI = m_module->GetMetaData();
  1670.  
  1671.         while (TRUE)
  1672.         {
  1673.             mdParamDef param[1];
  1674.             ULONG      numParams = 0;
  1675.  
  1676.             hr = pIMI->EnumParams(¶mEnum,
  1677.                                   GetToken(),
  1678.                                   param, 1, &numParams);
  1679.  
  1680.             if (SUCCEEDED(hr) && (numParams == 0))
  1681.             {
  1682.                 fCloseEnum = true;
  1683.                 hr = S_OK;
  1684.                 break;
  1685.             }
  1686.  
  1687.             if (FAILED(hr))
  1688.                 break;
  1689.  
  1690.             fCloseEnum = true;
  1691.  
  1692.             WCHAR name[BUF_SIZE];
  1693.             ULONG nameLen;
  1694.             ULONG seq;
  1695.  
  1696.             hr = pIMI->GetParamProps(param[0], 0,
  1697.                                      &seq, name, BUF_SIZE, &nameLen,
  1698.                                      NULL, NULL, NULL, NULL);
  1699.  
  1700.             if (SUCCEEDED(hr))
  1701.             {
  1702.                 char* newName = new char[nameLen];
  1703.                 _ASSERTE(newName != NULL);
  1704.  
  1705.                 unsigned int i;
  1706.  
  1707.                 for (i = 0; i < nameLen; i++)
  1708.                     newName[i] = name[i];
  1709.  
  1710.                 if (m_isStatic)
  1711.                     seq--;
  1712.  
  1713.                 if (seq < m_argCount)
  1714.                     m_arguments[seq].name = newName;
  1715.                 else
  1716.                 {
  1717.                     g_pShell->Write(L"Superflous parameter name detected: "
  1718.                                     L"%s::%s Sequence=%d, name=%s\n",
  1719.                                     m_className, m_name, seq, name);
  1720.                     delete [] newName;
  1721.                 }
  1722.             }
  1723.             else
  1724.                 break;
  1725.         }
  1726.  
  1727.         if (fCloseEnum)
  1728.             pIMI->CloseEnum(paramEnum);
  1729.  
  1730.         // Give any unnamed aguments names now...
  1731.         for (i = 0; i < m_argCount; i++)
  1732.         {
  1733.             if (m_arguments[i].name == NULL)
  1734.             {
  1735.                 char *newName = new char[07];
  1736.                 _ASSERTE(newName != NULL);
  1737.                 sprintf(newName, "Arg%d", i);
  1738.                 m_arguments[i].name = newName;
  1739.             }
  1740.         }
  1741.     }
  1742.  
  1743.     return (hr);
  1744. }
  1745.  
  1746.  
  1747. DebuggerFunction::~DebuggerFunction()
  1748. {
  1749.  
  1750.     if (m_arguments != NULL)
  1751.     {
  1752.         unsigned int i;
  1753.  
  1754.         for (i = 0; i < m_argCount; i++)
  1755.             delete [] (char *) m_arguments[i].name;
  1756.  
  1757.         delete [] m_arguments;
  1758.     }
  1759.  
  1760.     delete m_nativeCode;
  1761.     delete m_ilCode;
  1762.     delete [] m_name;
  1763.     delete [] m_className;
  1764.     delete [] m_namespaceName;
  1765.  
  1766.     g_pShell->m_invalidCache = false;
  1767.  
  1768.     if (m_ifunction != NULL)
  1769.         RELEASE(m_ifunction);
  1770.  
  1771.     if (m_symMethod)
  1772.     {
  1773.         if (m_SPOffsets)
  1774.             delete [] m_SPOffsets;
  1775.         
  1776.         if (m_SPDocuments)
  1777.         {
  1778.             for (int i = 0; i < m_SPCount; i++)
  1779.                 m_SPDocuments[i]->Release();
  1780.             
  1781.             delete [] m_SPDocuments;
  1782.         }
  1783.         
  1784.         if (m_SPLines)
  1785.             delete [] m_SPLines;
  1786.         
  1787.         RELEASE(m_symMethod);
  1788.     }
  1789. }
  1790.  
  1791. //
  1792. // Find the lowest line number that corresponds to a given IP with the method.
  1793. //
  1794. HRESULT DebuggerFunction::FindLineFromIP(UINT_PTR ip,
  1795.                                          DebuggerSourceFile **pDoc,
  1796.                                          unsigned int *line)
  1797. {
  1798.     HRESULT hr = S_FALSE;
  1799.  
  1800.     *pDoc = NULL;
  1801.     *line = 0;
  1802.  
  1803.     unsigned int i;
  1804.  
  1805.     // Make sure we've got the most recent copy....
  1806.     if (g_pShell->m_cEditAndContinues != m_nEditAndContinueLastSynched)
  1807.     {
  1808.        hr = CacheSequencePoints();
  1809.        
  1810.         if (FAILED( hr ) )
  1811.             return hr;
  1812.             
  1813.         m_nEditAndContinueLastSynched = g_pShell->m_cEditAndContinues;
  1814.     }
  1815.  
  1816.     // Only search if we have something to search over
  1817.     if (m_SPCount > 0)
  1818.     {
  1819.         // If ip is lower than the first ip...
  1820.         if (m_SPOffsets[0] <= ip)
  1821.         {
  1822.             // Find the first entry that corresponds to this ip.
  1823.             for (i = 0; i < m_SPCount; i++)
  1824.                 if (m_SPOffsets[i] >= ip)
  1825.                     break;
  1826.  
  1827.             // If not an exact match, then we're one too high.
  1828.             if (((i == m_SPCount) || (m_SPOffsets[i] != ip)) && (i > 0))
  1829.                 i--;
  1830.  
  1831.             *line = m_SPLines[i];
  1832.             VERIFY(*pDoc = GetModule()->ResolveSourceFile(m_SPDocuments[i]));
  1833.  
  1834.             hr = S_OK;
  1835.         }
  1836.     }
  1837.  
  1838.     return hr;
  1839. }
  1840.  
  1841.  
  1842. //
  1843. // Get the line stepping range for the given ip.
  1844. //
  1845.  
  1846. void DebuggerFunction::GetStepRangesFromIP(UINT_PTR ip, 
  1847.                                            COR_DEBUG_STEP_RANGE **range,
  1848.                                            SIZE_T *rangeCount)
  1849. {
  1850.     HRESULT hr;
  1851.     //
  1852.     // !!! Really, we should find _all_ source lines, not just one. (?)
  1853.     //
  1854.  
  1855.     DebuggerSourceFile *file = NULL;
  1856.     unsigned int line;
  1857.  
  1858.     *range = NULL;
  1859.     *rangeCount = 0;
  1860.  
  1861.     hr = FindLineFromIP(ip, &file, &line);
  1862.  
  1863.     if (FAILED(hr))
  1864.     {
  1865.         g_pShell->ReportError(hr);
  1866.         return;
  1867.     }
  1868.  
  1869.     if (file == NULL || !file->LoadText(g_pShell->m_currentSourcesPath, false))
  1870.         return;
  1871.  
  1872.     ULONG32 *rangeArray = NULL;
  1873.     ULONG32 rangeArraySize = 0;
  1874.  
  1875.     // How many ranges are there?
  1876.     if (m_symMethod)
  1877.     {
  1878.         hr = m_symMethod->GetRanges(file->GetDocument(),
  1879.                                     line, 0,
  1880.                                     0, &rangeArraySize, NULL);
  1881.  
  1882.         if (FAILED(hr))
  1883.         {
  1884.             g_pShell->ReportError(hr);
  1885.             return;
  1886.         }
  1887.     }
  1888.  
  1889.     if (rangeArraySize > 0)
  1890.     {
  1891.         // Make room and get the ranges.
  1892.         rangeArray = (ULONG32*)_alloca(sizeof(ULONG32) * rangeArraySize);
  1893.         _ASSERTE(rangeArray != NULL);
  1894.     
  1895.         hr = m_symMethod->GetRanges(file->GetDocument(),
  1896.                                     line, 0,
  1897.                                     rangeArraySize,
  1898.                                     &rangeArraySize,
  1899.                                     rangeArray);
  1900.  
  1901.         if (FAILED(hr))
  1902.         {
  1903.             g_pShell->ReportError(hr);
  1904.             return;
  1905.         }
  1906.     
  1907.         // lineRangeCount should be a reasonable approximation of
  1908.         // memory to allocate.
  1909.         *range = new COR_DEBUG_STEP_RANGE[rangeArraySize / 2]; 
  1910.         _ASSERTE(*range != NULL);
  1911.  
  1912.         COR_DEBUG_STEP_RANGE *r = *range;
  1913.  
  1914.         for (int i = 0; i < rangeArraySize; i += 2)
  1915.         {
  1916.             r->startOffset = rangeArray[i];
  1917.             r->endOffset = rangeArray[i+1];
  1918.  
  1919.             r++;
  1920.         }
  1921.     }
  1922.     else
  1923.         *range = NULL;
  1924.  
  1925.     *rangeCount = rangeArraySize / 2;
  1926. }
  1927.  
  1928.  
  1929. //
  1930. // Given a scope, determine how many local vars are "active" at the given
  1931. // line number. The count includes any locals that are active in scopes
  1932. // that are children of the given scope.
  1933. //
  1934. void DebuggerFunction::CountActiveLocalVars(ISymUnmanagedScope* head,
  1935.                                             unsigned int ip,
  1936.                                             unsigned int* varCount)
  1937. {
  1938.     if (head != NULL)
  1939.     {
  1940.         ULONG32 startOffset, endOffset;
  1941.  
  1942.         HRESULT hr = head->GetStartOffset(&startOffset);
  1943.         _ASSERTE(SUCCEEDED(hr));
  1944.         hr = head->GetEndOffset(&endOffset);
  1945.         _ASSERTE(SUCCEEDED(hr));
  1946.         
  1947.         if ((ip >= startOffset) && (ip <= endOffset))
  1948.         {
  1949.             ULONG32 childCount;
  1950.  
  1951.             // How many children?
  1952.             hr = head->GetChildren(0, &childCount, NULL);
  1953.  
  1954.             if (FAILED(hr))
  1955.             {
  1956.                 g_pShell->ReportError(hr);
  1957.                 return;
  1958.             }
  1959.  
  1960.             if (childCount > 0)
  1961.             {
  1962.                 // Make room for the children
  1963.                 ISymUnmanagedScope **children =
  1964.                     (ISymUnmanagedScope**)_alloca(sizeof(ISymUnmanagedScope*) * childCount);
  1965.                 _ASSERTE(children != NULL);
  1966.  
  1967.                 // Get the children
  1968.                 hr = head->GetChildren(childCount, &childCount, children);
  1969.  
  1970.                 if (FAILED(hr))
  1971.                 {
  1972.                     g_pShell->ReportError(hr);
  1973.                     return;
  1974.                 }
  1975.                 
  1976.                 for (int i = 0; i < childCount; i++)
  1977.                 {
  1978.                     CountActiveLocalVars(children[i], ip, varCount);
  1979.                     RELEASE(children[i]);
  1980.                 }
  1981.             }
  1982.             
  1983.             ULONG32 vc;
  1984.             hr = head->GetLocalCount(&vc);
  1985.             _ASSERTE(SUCCEEDED(hr));
  1986.             
  1987.             *varCount += vc;
  1988.         }
  1989.     }
  1990. }
  1991.  
  1992.  
  1993. //
  1994. // Given a scope and an array of DebuggerVarInfo pointers, fill up the array
  1995. // with pointers to every "active" local variable within the scope, including
  1996. // any active locals in child scopes. The size of the varPtrs array is
  1997. // passed in as varCount and is used for bounds checking.
  1998. //
  1999. void DebuggerFunction::FillActiveLocalVars(ISymUnmanagedScope* head,
  2000.                                            unsigned int ip,
  2001.                                            unsigned int varCount,
  2002.                                            unsigned int* currentVar,
  2003.                                            DebuggerVariable* varPtrs)
  2004. {
  2005.     if (head != NULL)
  2006.     {
  2007.         ULONG32 startOffset, endOffset;
  2008.  
  2009.         HRESULT hr = head->GetStartOffset(&startOffset);
  2010.         _ASSERTE(SUCCEEDED(hr));
  2011.         hr = head->GetEndOffset(&endOffset);
  2012.         _ASSERTE(SUCCEEDED(hr));
  2013.         
  2014.         if ((ip >= startOffset) && (ip <= endOffset))
  2015.         {
  2016.             ULONG32 childCount;
  2017.  
  2018.             // How many children?
  2019.             hr = head->GetChildren(0, &childCount, NULL);
  2020.  
  2021.             if (FAILED(hr))
  2022.             {
  2023.                 g_pShell->ReportError(hr);
  2024.                 return;
  2025.             }
  2026.  
  2027.             if (childCount > 0)
  2028.             {
  2029.                 // Make room for the children
  2030.                 ISymUnmanagedScope **children =
  2031.                     (ISymUnmanagedScope**)_alloca(sizeof(ISymUnmanagedScope*) * childCount);
  2032.                 _ASSERTE(children != NULL);
  2033.  
  2034.                 // Get the children
  2035.                 hr = head->GetChildren(childCount, &childCount, children);
  2036.  
  2037.                 if (FAILED(hr))
  2038.                 {
  2039.                     g_pShell->ReportError(hr);
  2040.                     return;
  2041.                 }
  2042.                 
  2043.                 for (int i = 0; i < childCount; i++)
  2044.                 {
  2045.                     FillActiveLocalVars(children[i], ip, varCount,
  2046.                                         currentVar, varPtrs);
  2047.                     RELEASE(children[i]);
  2048.                 }
  2049.             }
  2050.  
  2051.             // Fill in any locals on this scope.
  2052.             ULONG32 localCount;
  2053.  
  2054.             // How many locals?
  2055.             hr = head->GetLocalCount(&localCount);
  2056.  
  2057.             if (FAILED(hr))
  2058.             {
  2059.                 g_pShell->ReportError(hr);
  2060.                 return;
  2061.             }
  2062.  
  2063.             if (localCount > 0)
  2064.             {
  2065.                 // Make room for the localc
  2066.                 ISymUnmanagedVariable **locals =
  2067.                     (ISymUnmanagedVariable**)_alloca(sizeof(ISymUnmanagedVariable*) *
  2068.                                             localCount);
  2069.                 _ASSERTE(locals != NULL);
  2070.                 
  2071.                 hr = head->GetLocals(localCount, &localCount, locals);
  2072.             
  2073.                 if (FAILED(hr))
  2074.                 {
  2075.                     g_pShell->ReportError(hr);
  2076.                     return;
  2077.                 }
  2078.  
  2079.                 for (int i = 0; i < localCount; i++)
  2080.                 {
  2081.                     _ASSERTE(*currentVar < varCount);
  2082.  
  2083.                     // Get the size of the name.
  2084.                     ULONG32 nameSize;
  2085.  
  2086.                     hr = locals[i]->GetName(0, &nameSize, NULL);
  2087.                     
  2088.                     if (FAILED(hr))
  2089.                     {
  2090.                         g_pShell->ReportError(hr);
  2091.                         return;
  2092.                     }
  2093.  
  2094.                     // Allocate space for the name.
  2095.                     varPtrs[*currentVar].m_name = new WCHAR[nameSize + 1];
  2096.  
  2097.                     if (varPtrs[*currentVar].m_name == NULL)
  2098.                     {
  2099.                         g_pShell->ReportError(E_OUTOFMEMORY);
  2100.                         return;
  2101.                     }
  2102.  
  2103.                     // Get the name.
  2104.                     hr = locals[i]->GetName(nameSize + 1, &nameSize,
  2105.                                             varPtrs[*currentVar].m_name);
  2106.                 
  2107.                     if (FAILED(hr))
  2108.                     {
  2109.                         g_pShell->ReportError(hr);
  2110.                         return;
  2111.                     }
  2112.  
  2113. #ifdef _DEBUG
  2114.                     ULONG32 addrKind;
  2115.                     hr = locals[i]->GetAddressKind(&addrKind);
  2116.                     _ASSERTE(addrKind == ADDR_IL_OFFSET);
  2117. #endif                    
  2118.  
  2119.                     hr = locals[i]->GetAddressField1(&(varPtrs[*currentVar].m_varNumber));
  2120.  
  2121.                     if (FAILED(hr))
  2122.                     {
  2123.                         g_pShell->ReportError(hr);
  2124.                         return;
  2125.                     }
  2126.  
  2127.                     (*currentVar)++;
  2128.                 }
  2129.             }
  2130.         }
  2131.     }
  2132. }
  2133.  
  2134.  
  2135. //
  2136. // Build a list of the active local variables within a method at a given IP.
  2137. //
  2138. bool DebuggerFunction::GetActiveLocalVars(UINT_PTR ip,
  2139.                                           DebuggerVariable** vars,
  2140.                                           unsigned int* count)
  2141. {
  2142.     HRESULT hr = S_OK;
  2143.  
  2144.     *vars = NULL;
  2145.     *count = 0;
  2146.  
  2147.     // Grab the root scope for this method.
  2148.     ISymUnmanagedScope *rootScope = NULL;
  2149.  
  2150.     if (m_symMethod)
  2151.     {
  2152.         hr = m_symMethod->GetRootScope(&rootScope);
  2153.  
  2154.         if (FAILED(hr))
  2155.         {
  2156.             g_pShell->ReportError(hr);
  2157.             return false;
  2158.         }
  2159.     }
  2160.  
  2161.     // No work to do if there is no scope info for this method!
  2162.     if (!rootScope)
  2163.         return false;
  2164.  
  2165.     // Count the active locals.
  2166.     unsigned int localCount = 0;
  2167.  
  2168.     CountActiveLocalVars(rootScope, ip, &localCount);
  2169.  
  2170.     // No work to do if there aren't any locals in scope.
  2171.     if (localCount == 0)
  2172.     {
  2173.         rootScope->Release();
  2174.         return true;
  2175.     }
  2176.  
  2177.     // Allocate and fillup a list of DebuggerVariable pointers to
  2178.     // each variable.
  2179.     DebuggerVariable *varPtrs = new DebuggerVariable[localCount];
  2180.     _ASSERTE(varPtrs != NULL);
  2181.  
  2182.     if (varPtrs != NULL)
  2183.     {
  2184.         unsigned int currentVar = 0;
  2185.  
  2186.         FillActiveLocalVars(rootScope, ip, localCount,
  2187.                             ¤tVar, varPtrs);
  2188.     }
  2189.     else
  2190.         localCount = 0;
  2191.  
  2192.     *vars = varPtrs;
  2193.     *count = localCount;
  2194.  
  2195.     rootScope->Release();
  2196.  
  2197.     return true;
  2198. }
  2199.  
  2200. DebuggerFunction *DebuggerFunction::FromCorDebug(ICorDebugFunction *function)
  2201. {
  2202.     mdMethodDef md;
  2203.     HRESULT hr;
  2204.  
  2205.     // Get the method def token for function
  2206.     hr = function->GetToken(&md);
  2207.  
  2208.     // Error check
  2209.     if (FAILED(hr))
  2210.     {
  2211.         g_pShell->ReportError(hr);
  2212.         return NULL;
  2213.     }
  2214.  
  2215.     // Now get the module interface, so we can get a pointer to the CorDbg
  2216.     // DebuggerModule object
  2217.     ICorDebugModule *imodule;
  2218.     hr = function->GetModule(&imodule);
  2219.     
  2220.     // Error check
  2221.     if (FAILED(hr))
  2222.     {
  2223.         g_pShell->ReportError(hr);
  2224.         return NULL;
  2225.     }
  2226.  
  2227.     // Get a pointer to the CorDbg module
  2228.     DebuggerModule *m = DebuggerModule::FromCorDebug(imodule);
  2229.     _ASSERTE(m);  // should never fail
  2230.  
  2231.     // Release the interface
  2232.     imodule->Release();
  2233.  
  2234.     // Use the debugger module to resolve the function to a DebuggerFunction ptr
  2235.     return (m->ResolveFunction(md, function));
  2236. }
  2237.  
  2238. HRESULT DebuggerFunction::LoadCode(BOOL native)
  2239. {
  2240.     _ASSERTE( g_pShell != NULL );
  2241.     if (native)
  2242.     {
  2243. //        if (m_nativeCode != NULL && !g_pShell->m_invalidCache ) 
  2244. //            return (S_OK);
  2245.  
  2246. //        if( g_pShell->m_invalidCache )
  2247. //        {   //@todo: is this safe?
  2248. //            delete m_nativeCode;
  2249. //        }
  2250.  
  2251.         ICorDebugCode *icode;
  2252.         HRESULT hr = m_ifunction->GetNativeCode(&icode);
  2253.  
  2254.         if (FAILED(hr) && hr != CORDBG_E_CODE_NOT_AVAILABLE)
  2255.             return (hr);
  2256.  
  2257.         ULONG32 size;
  2258.         icode->GetSize(&size);
  2259.  
  2260.         m_nativeCode = new BYTE [size];
  2261.         _ASSERTE(m_nativeCode != NULL);
  2262.         m_nativeCodeSize = size;
  2263.  
  2264.         if (m_nativeCode == NULL)
  2265.             return (E_OUTOFMEMORY);
  2266.  
  2267.         hr = icode->GetCode(0, size, size, 
  2268.                             m_nativeCode, &m_nativeCodeSize);
  2269.         if (FAILED(hr))
  2270.             return (hr);
  2271.  
  2272.         icode->Release();
  2273.  
  2274.         if (FAILED(hr))
  2275.         {
  2276.             delete m_nativeCode;
  2277.             return (hr);
  2278.         }
  2279.  
  2280.         return (S_OK);
  2281.     }
  2282.     else
  2283.     {
  2284.         if (m_ilCode != NULL)
  2285.             return (S_OK);
  2286.  
  2287.         ICorDebugCode *icode;
  2288.         HRESULT hr = m_ifunction->GetILCode(&icode);
  2289.         if (FAILED(hr))
  2290.             return (hr);
  2291.  
  2292.         ULONG32 size;
  2293.         icode->GetSize(&size);
  2294.  
  2295.         m_ilCode = new BYTE [size];
  2296.         m_ilCodeSize = size;
  2297.  
  2298.         if (m_ilCode == NULL)
  2299.             return (E_OUTOFMEMORY);
  2300.  
  2301.         hr = icode->GetCode(0, size, size, 
  2302.                             m_ilCode, &m_ilCodeSize);
  2303.         if (FAILED(hr))
  2304.             return (hr);
  2305.  
  2306.         icode->Release();
  2307.  
  2308.         if (FAILED(hr))
  2309.         {
  2310.             delete m_ilCode;
  2311.             return (FALSE);
  2312.         }
  2313.  
  2314.         return (S_OK);
  2315.     }
  2316. }
  2317.  
  2318. BOOL DebuggerFunction::ValidateInstruction(BOOL native, SIZE_T offset)
  2319. {
  2320.     if (FAILED(LoadCode(native)))
  2321.         return (FALSE);
  2322.  
  2323.     if (native)
  2324.     {
  2325.         if (offset >= m_nativeCodeSize)
  2326.             return (false);
  2327.     }
  2328.     else
  2329.     {
  2330.         if (offset >= m_ilCodeSize)
  2331.             return (false);
  2332.     }
  2333.  
  2334.     SIZE_T walk = 0;
  2335.  
  2336. #ifdef _INTERNAL_DEBUG_SUPPORT_
  2337.     while (walk < offset)
  2338.         walk = WalkInstruction(native, walk);
  2339. #endif
  2340.  
  2341.     return (walk == offset);
  2342. }
  2343.  
  2344. /* ------------------------------------------------------------------------- *
  2345.  * DebuggerCodeBreakpoint
  2346.  * ------------------------------------------------------------------------- */
  2347.  
  2348. DebuggerCodeBreakpoint::DebuggerCodeBreakpoint(int breakpointID, 
  2349.                                                DebuggerModule *module,
  2350.                                                DebuggerFunction *function, 
  2351.                                                SIZE_T offset, BOOL il,
  2352.                                                DWORD threadID)
  2353.     : m_id(breakpointID), m_module(module), m_function(function), 
  2354.       m_offset(offset), m_il(il), m_threadID(threadID),
  2355.       m_ibreakpoint(NULL), m_parent(NULL)
  2356. {
  2357.     m_next = m_module->m_breakpoints;
  2358.     m_module->m_breakpoints = this;
  2359.     m_id = breakpointID;
  2360. }
  2361.  
  2362. DebuggerCodeBreakpoint::DebuggerCodeBreakpoint(
  2363.                             int breakpointID, DebuggerModule *module,
  2364.                             DebuggerSourceCodeBreakpoint *parent, 
  2365.                             DebuggerFunction *function, SIZE_T offset, BOOL il,
  2366.                             DWORD threadID)
  2367.     : m_id(breakpointID), m_module(module), m_function(function), 
  2368.       m_offset(offset), m_il(il), 
  2369.       m_threadID(threadID), 
  2370.       m_ibreakpoint(NULL), m_parent(parent)
  2371. {
  2372.     m_next = parent->m_breakpoints;
  2373.     parent->m_breakpoints = this;
  2374.     m_id = parent->m_id;
  2375. }
  2376.  
  2377. DebuggerCodeBreakpoint::~DebuggerCodeBreakpoint()
  2378. {
  2379.     DebuggerCodeBreakpoint  **next;
  2380.  
  2381.     //
  2382.     // Remove either global list or parent list
  2383.     //
  2384.  
  2385.     if (m_parent == NULL)
  2386.         next = &m_module->m_breakpoints;
  2387.     else
  2388.         next = &m_parent->m_breakpoints;
  2389.  
  2390.     while ((*next) != this)
  2391.         next = &((*next)->m_next);
  2392.  
  2393.     *next = (*next)->m_next;
  2394.  
  2395.     //
  2396.     // Destroy the cor breakpoint
  2397.     //
  2398.  
  2399.     if (m_ibreakpoint != NULL)
  2400.     {
  2401.         m_ibreakpoint->Activate(FALSE);
  2402.         m_ibreakpoint->Release();
  2403.     }
  2404. }
  2405.  
  2406. bool DebuggerCodeBreakpoint::Activate()
  2407. {
  2408.     if (m_ibreakpoint == NULL && m_function != NULL)
  2409.     {
  2410.         ICorDebugCode *icode;
  2411.  
  2412.         HRESULT hr;
  2413.  
  2414.         if (m_il)
  2415.             hr = m_function->m_ifunction->GetILCode(&icode);
  2416.         else
  2417.             hr = m_function->m_ifunction->GetNativeCode(&icode);
  2418.  
  2419.         if (SUCCEEDED(hr) || hr == CORDBG_E_CODE_NOT_AVAILABLE)
  2420.             hr = icode->CreateBreakpoint(m_offset, &m_ibreakpoint);
  2421.     }
  2422.  
  2423.     if (m_ibreakpoint != NULL)
  2424.     {
  2425.         m_ibreakpoint->Activate(TRUE);
  2426.         return (true);
  2427.     }
  2428.     else
  2429.         return (false);
  2430. }
  2431.  
  2432. void DebuggerCodeBreakpoint::Deactivate()
  2433. {
  2434.     if (m_ibreakpoint != NULL)
  2435.     {
  2436.         m_ibreakpoint->Activate(FALSE);
  2437.         m_ibreakpoint->Release();
  2438.         m_ibreakpoint = NULL;
  2439.     }
  2440. }
  2441.  
  2442. bool DebuggerCodeBreakpoint::Match(ICorDebugBreakpoint *ibreakpoint)
  2443. {
  2444.     return (ibreakpoint == m_ibreakpoint);
  2445. }
  2446.  
  2447. void DebuggerCodeBreakpoint::Print()
  2448. {
  2449.     g_pShell->Write(L"%s+0x%x(%s) [%sactive]", 
  2450.                     m_function->GetName(), m_offset, 
  2451.                     m_il ? L"il" : L"native",
  2452.                     m_ibreakpoint == NULL ? L"in" : L"");
  2453. }
  2454.  
  2455. DebuggerSourceCodeBreakpoint::DebuggerSourceCodeBreakpoint(
  2456.                                                int breakpointID,
  2457.                                                DebuggerSourceFile *file, 
  2458.                                                SIZE_T lineNumber,
  2459.                                                DWORD threadID)
  2460.     : DebuggerCodeBreakpoint(breakpointID, file->m_module, NULL, 
  2461.                              0, FALSE, threadID), 
  2462.       m_file(file), m_lineNumber(lineNumber), m_breakpoints(NULL)
  2463. {
  2464.     DebuggerModule          *m = file->m_module;
  2465.  
  2466.     // GetMethodFromDocumentPosition to get an ISymUnmanagedMethod from this doc.
  2467.     ISymUnmanagedMethod *pSymMethod;
  2468.  
  2469.     HRESULT hr = m->GetSymbolReader()->GetMethodFromDocumentPosition(
  2470.                                                         file->GetDocument(),
  2471.                                                         lineNumber, 0,
  2472.                                                         &pSymMethod);
  2473.  
  2474.     if (FAILED(hr))
  2475.     {
  2476.         g_pShell->Write(L"Failed to find method to match source line. "
  2477.                         L"Unable to set breakpoint.\n");
  2478.         g_pShell->ReportError(hr);
  2479.         return;
  2480.     }
  2481.     
  2482.     // Make a regular breakpoint a the start of each line range.
  2483.     ULONG32 *rangeArray = NULL;
  2484.     ULONG32 rangeArraySize = 0;
  2485.  
  2486.     // How many ranges are there?
  2487.     hr = pSymMethod->GetRanges(file->GetDocument(),
  2488.                                lineNumber, 0,
  2489.                                0, &rangeArraySize, NULL);
  2490.  
  2491.     if (FAILED(hr))
  2492.     {
  2493.         g_pShell->ReportError(hr);
  2494.         return;
  2495.     }
  2496.  
  2497.     if (rangeArraySize > 0)
  2498.     {
  2499.         // Make room and get the ranges.
  2500.         rangeArray = (ULONG32*)_alloca(sizeof(ULONG32) * rangeArraySize);
  2501.         _ASSERTE(rangeArray != NULL);
  2502.     
  2503.         hr = pSymMethod->GetRanges(file->GetDocument(),
  2504.                                    lineNumber, 0,
  2505.                                    rangeArraySize,
  2506.                                    &rangeArraySize,
  2507.                                    rangeArray);
  2508.  
  2509.         if (FAILED(hr))
  2510.         {
  2511.             g_pShell->ReportError(hr);
  2512.             return;
  2513.         }
  2514.  
  2515.         DebuggerFunction *f = m_function = m->ResolveFunction(pSymMethod, NULL);
  2516.  
  2517.         if (rangeArraySize == 2)
  2518.         {
  2519.             m_offset = rangeArray[0];
  2520.             m_il = TRUE;
  2521.         }
  2522.         else
  2523.         {
  2524.             for (int i = 0; i < rangeArraySize; i += 2)
  2525.             {
  2526.                 if (i > 0 && (rangeArray [i-1] == rangeArray [i]))
  2527.                     continue;
  2528.  
  2529.                 new DebuggerCodeBreakpoint(breakpointID, file->m_module, 
  2530.                                          this, f, rangeArray[i], TRUE, 
  2531.                                          m_threadID);
  2532.             }
  2533.         }
  2534.     }
  2535. }
  2536.  
  2537. DebuggerSourceCodeBreakpoint::~DebuggerSourceCodeBreakpoint()
  2538. {
  2539.     while (m_breakpoints != NULL)
  2540.         delete m_breakpoints;
  2541. }
  2542.  
  2543. bool DebuggerSourceCodeBreakpoint::Activate()
  2544. {
  2545.     bool result = true;
  2546.  
  2547.     DebuggerCodeBreakpoint::Activate();
  2548.  
  2549.     DebuggerCodeBreakpoint *b = m_breakpoints;
  2550.  
  2551.     while (b != NULL)
  2552.     {
  2553.         result = b->Activate() && result;
  2554.         b = b->m_next;
  2555.     }
  2556.  
  2557.     return (result);
  2558. }
  2559.  
  2560. void DebuggerSourceCodeBreakpoint::Deactivate()
  2561. {
  2562.     DebuggerCodeBreakpoint::Deactivate();
  2563.  
  2564.     DebuggerCodeBreakpoint *b = m_breakpoints;
  2565.  
  2566.     while (b != NULL)
  2567.     {
  2568.         b->Deactivate();
  2569.         b = b->m_next;
  2570.     }
  2571. }
  2572.  
  2573. bool DebuggerSourceCodeBreakpoint::Match(ICorDebugBreakpoint *ibreakpoint)
  2574. {
  2575.     if (ibreakpoint == m_ibreakpoint)
  2576.         return (true);
  2577.  
  2578.     DebuggerCodeBreakpoint *bp = m_breakpoints;
  2579.     while (bp != NULL)
  2580.     {
  2581.         if (bp->m_ibreakpoint == ibreakpoint)
  2582.             return (true);
  2583.         bp = bp->m_next;
  2584.     }
  2585.  
  2586.     return (false);
  2587. }
  2588.  
  2589. void DebuggerSourceCodeBreakpoint::Print()
  2590. {
  2591.     DebuggerCodeBreakpoint *bp = m_breakpoints;
  2592.  
  2593.     if (bp == NULL)
  2594.         DebuggerCodeBreakpoint::Print();
  2595.     else
  2596.         while (bp != NULL)
  2597.         {
  2598.             bp->Print();
  2599.             bp = bp->m_next;
  2600.         }
  2601. }
  2602.  
  2603. /* ------------------------------------------------------------------------- *
  2604.  * StepperHashTable class
  2605.  * ------------------------------------------------------------------------- */
  2606.  
  2607.  
  2608. HRESULT StepperHashTable::Initialize()
  2609. {
  2610.     HRESULT hr = NewInit(m_iBuckets, 
  2611.                          sizeof(StepperHashEntry), 0xffff);
  2612.     if (FAILED(hr))
  2613.           return (hr);
  2614.  
  2615.     m_initialized = true;
  2616.     return S_OK;
  2617. }
  2618.  
  2619.  
  2620. HRESULT StepperHashTable::AddStepper(ICorDebugStepper *pStepper)
  2621. {
  2622.     if (!m_initialized)
  2623.     {
  2624.         HRESULT hr = NewInit(m_iBuckets, 
  2625.                              sizeof(StepperHashEntry), 0xffff);
  2626.         if (FAILED(hr))
  2627.             return (hr);
  2628.  
  2629.         m_initialized = true;
  2630.     }
  2631.  
  2632.     StepperHashEntry *entry = (StepperHashEntry *) Add(HASH(pStepper));
  2633.  
  2634.     if (entry == NULL)
  2635.         return (E_FAIL);
  2636.     else
  2637.         entry->pStepper = pStepper;
  2638.  
  2639.     pStepper->AddRef(); //don't want this to disappear from under
  2640.         //the table's feet
  2641.  
  2642.     return (S_OK);
  2643. }
  2644.  
  2645. bool StepperHashTable::IsStepperPresent(ICorDebugStepper *pStepper)
  2646. {
  2647.     if (!m_initialized)
  2648.         return false;
  2649.  
  2650.     StepperHashEntry *entry 
  2651.     = (StepperHashEntry *) Find(HASH(pStepper), KEY(pStepper)); 
  2652.     if (entry == NULL)
  2653.         return false;
  2654.     else
  2655.         return true;
  2656. }
  2657.  
  2658. BOOL StepperHashTable::RemoveStepper(ICorDebugStepper *pStepper)
  2659. {
  2660.     if (!m_initialized)
  2661.         return (FALSE);
  2662.  
  2663.     StepperHashEntry *entry 
  2664.     = (StepperHashEntry *) Find(HASH(pStepper), KEY(pStepper));
  2665.  
  2666.     if (entry == NULL)
  2667.         return (FALSE);
  2668.  
  2669.     Delete(HASH(pStepper), (HASHENTRY *) entry);
  2670.  
  2671.     RELEASE(pStepper);
  2672.  
  2673.     return (TRUE);
  2674. }
  2675.  
  2676. void StepperHashTable::ReleaseAll()
  2677. {
  2678.     if (!m_initialized)
  2679.         return;
  2680.  
  2681.     HASHFIND find;
  2682.     ICorDebugStepper *pStepper = NULL;
  2683.     
  2684.     pStepper = FindFirst(&find);
  2685.     while( pStepper != NULL)
  2686.     {
  2687.         RELEASE( pStepper );
  2688.         RemoveStepper( pStepper );
  2689.     
  2690.         pStepper = FindNext(&find);
  2691.     }
  2692.  
  2693.     Clear();    
  2694. }
  2695.  
  2696. ICorDebugStepper *StepperHashTable::FindFirst(HASHFIND *find)
  2697. {
  2698.     if (!m_initialized)
  2699.         return NULL;
  2700.         
  2701.     StepperHashEntry *entry = (StepperHashEntry *) FindFirstEntry(find);
  2702.     if (entry == NULL)
  2703.         return NULL;
  2704.     else
  2705.         return entry->pStepper;
  2706. }
  2707.  
  2708. ICorDebugStepper *StepperHashTable::FindNext(HASHFIND *find)
  2709. {
  2710.     if (!m_initialized)
  2711.         return NULL;
  2712.  
  2713.     StepperHashEntry *entry = (StepperHashEntry *) FindNextEntry(find);
  2714.     if (entry == NULL)
  2715.         return NULL;
  2716.     else
  2717.         return entry->pStepper;
  2718. }
  2719.  
  2720.