home *** CD-ROM | disk | FTP | other *** search
- #include "stdafx.h"
-
- #define BUF_SIZE 256
-
- /* ------------------------------------------------------------------------- *
- * Debugger base class
- * ------------------------------------------------------------------------- */
-
- DebuggerHashTable::~DebuggerHashTable()
- {
- HASHFIND find;
-
- for (DebuggerHashEntry *entry = (DebuggerHashEntry *) FindFirstEntry(&find);
- entry != NULL;
- entry = (DebuggerHashEntry *) FindNextEntry(&find))
- delete entry->pBase;
- }
-
- HRESULT DebuggerHashTable::AddBase(DebuggerBase *pBase)
- {
- if (!m_initialized)
- {
- HRESULT hr = NewInit(m_iBuckets,
- sizeof(DebuggerHashEntry), 0xffff);
- if (hr != S_OK)
- return (hr);
-
- m_initialized = true;
- }
-
- DebuggerHashEntry *entry = (DebuggerHashEntry *) Add(HASH(pBase->GetToken()));
-
- if (entry == NULL)
- return (E_FAIL);
- else
- entry->pBase = pBase;
-
- return (S_OK);
- }
-
- DebuggerBase *DebuggerHashTable::GetBase(ULONG id)
- {
- if (!m_initialized)
- return (NULL);
-
- DebuggerHashEntry *entry
- = (DebuggerHashEntry *) Find(HASH(id), KEY(id));
- if (entry == NULL)
- return (NULL);
- else
- return (entry->pBase);
- }
-
- BOOL DebuggerHashTable::RemoveBase(ULONG id)
- {
- if (!m_initialized)
- return (FALSE);
-
- DebuggerHashEntry *entry
- = (DebuggerHashEntry *) Find(HASH(id), KEY(id));
-
- if (entry == NULL)
- return (FALSE);
-
- DebuggerBase *base = entry->pBase;
-
- Delete(HASH(id), (HASHENTRY *) entry);
- delete base;
-
- return (TRUE);
- }
-
- void DebuggerHashTable::RemoveAll()
- {
- HASHFIND find;
-
- for (DebuggerHashEntry *entry = (DebuggerHashEntry *) FindFirstEntry(&find);
- entry != NULL;
- entry = (DebuggerHashEntry *) FindNextEntry(&find))
- delete entry->pBase;
-
- Clear();
- }
-
- DebuggerBase *DebuggerHashTable::FindFirst(HASHFIND *find)
- {
- DebuggerHashEntry *entry = (DebuggerHashEntry *) FindFirstEntry(find);
- if (entry == NULL)
- return (NULL);
- else
- return (entry->pBase);
- }
-
- DebuggerBase *DebuggerHashTable::FindNext(HASHFIND *find)
- {
- DebuggerHashEntry *entry = (DebuggerHashEntry *) FindNextEntry(find);
- if (entry == NULL)
- return (NULL);
- else
- return (entry->pBase);
- }
-
- /* ------------------------------------------------------------------------- *
- * DebuggerClass
- * ------------------------------------------------------------------------- */
- DebuggerClass::DebuggerClass (ICorDebugClass *pClass)
- : DebuggerBase ((ULONG)pClass),
- m_szName (NULL),
- m_szNamespace (NULL)
- {
- }
-
- DebuggerClass::~DebuggerClass ()
- {
- delete m_szName;
- delete m_szNamespace;
- }
-
- void DebuggerClass::SetName (WCHAR *pszName, WCHAR *pszNamespace)
- {
- if (pszName != NULL)
- {
- int iLength = wcslen (pszName);
- if ((m_szName = new WCHAR [iLength+1]) != NULL)
- wcscpy (m_szName, pszName);
- }
-
- if (pszNamespace != NULL)
- {
- int iLength = wcslen (pszNamespace);
- if ((m_szNamespace = new WCHAR [iLength+1]) != NULL)
- wcscpy (m_szNamespace, pszNamespace);
- }
- }
-
- WCHAR *DebuggerClass::GetName (void)
- {
- return m_szName;
- }
-
- WCHAR *DebuggerClass::GetNamespace (void)
- {
- return m_szNamespace;
- }
-
- /* ------------------------------------------------------------------------- *
- * DebuggerModule
- * ------------------------------------------------------------------------- */
-
- DebuggerModule::DebuggerModule(ICorDebugModule* imodule)
- : DebuggerBase((ULONG)imodule),
- m_sourceFiles(11), m_functions(37), m_functionsByIF(11), m_szName(NULL),
- m_loadedClasses(11), m_breakpoints(NULL), m_pISymUnmanagedReader(NULL)
- {
- // Also initialize the source file array
- for (int i=0; i<MAX_SF_BUCKETS; i++)
- m_pModSourceFile [i] = NULL;
- // Indicate that source file names are not yet loaded
- m_fSFNamesLoaded = false;
-
- imodule->AddRef();
- }
-
- HRESULT DebuggerModule::Init()
- {
- // Get the necessary metadata interfaces now...
- HRESULT hr = GetICorDebugModule()->GetMetaDataInterface(
- IID_IMetaDataImport,
- (IUnknown**)&m_pIMetaDataImport);
-
- if (FAILED(hr))
- return hr;
-
- // Get the module name
- WCHAR moduleName[MAX_PATH];
- ULONG32 nameLen;
-
- hr = GetICorDebugModule()->GetName(MAX_PATH, &nameLen, moduleName);
- _ASSERTE(nameLen <= MAX_PATH);
-
- // Don't get a reader if its a dynamic module... syms for those
- // come in on update later.
- BOOL isDynamic = FALSE;
- hr = GetICorDebugModule()->IsDynamic(&isDynamic);
- _ASSERTE(SUCCEEDED(hr));
-
- if (isDynamic)
- return hr;
-
- // Get a symbol binder.
- ISymUnmanagedBinder *binder;
- hr = CoCreateInstance(CLSID_CorSymBinder, NULL,
- CLSCTX_INPROC_SERVER,
- IID_ISymUnmanagedBinder,
- (void**)&binder);
-
- if (FAILED(hr))
- {
- g_pShell->Write(L"Error: couldn't get a CorSymBinder for "
- L"symbol loading.\n");
- return hr;
- }
-
- // Ask the binder for a reader for this module.
- hr = binder->GetReaderForFile(m_pIMetaDataImport,
- moduleName,
- NULL, /* no search path */
- &m_pISymUnmanagedReader);
-
- // Release the binder
- binder->Release();
-
- if (FAILED(hr))
- {
- g_pShell->Write(L"Warning: couldn't load symbols for %s\n",
- moduleName);
- return S_OK;
- }
-
- return hr;
- }
-
- DebuggerModule::~DebuggerModule()
- {
- while (m_breakpoints != NULL)
- {
- DebuggerCodeBreakpoint *bp = m_breakpoints->m_next;
- delete m_breakpoints;
- m_breakpoints = bp;
- }
-
- DebuggerBreakpoint *bp = g_pShell->m_breakpoints;
- while (bp != NULL)
- {
- if (bp->IsBoundToModule(this))
- bp->RemoveBoundModule(this);
-
- bp = bp->m_next;
- }
-
- GetICorDebugModule()->Release();
-
- if (m_pIMetaDataImport)
- m_pIMetaDataImport->Release();
-
- if (m_pISymUnmanagedReader)
- m_pISymUnmanagedReader->Release();
-
- // Also go through all the buckets and release the cached ModuleSourceFiles
- // Need to do it only if the cache has elements in it
- if (m_fSFNamesLoaded == true)
- {
- for (int i=0; i<MAX_SF_BUCKETS; i++)
- {
- ModuleSourceFile *pMod = m_pModSourceFile [i];
- ModuleSourceFile *pTemp = NULL;
-
- while (pMod)
- {
- pTemp = pMod;
- pMod = pTemp->GetNext();
- delete pTemp;
- }
- }
- }
-
- delete m_szName;
- }
-
- DebuggerSourceFile *DebuggerModule::LookupSourceFile(const WCHAR *name)
- {
- GUID g = {0};
- ISymUnmanagedDocument *doc;
-
- if (!m_pISymUnmanagedReader)
- return NULL;
-
- HRESULT hr = m_pISymUnmanagedReader->GetDocument((WCHAR*)name, g, g, g, &doc);
-
- _ASSERTE( doc != NULL );
- if (FAILED(hr))
- return (NULL);
- else
- return (ResolveSourceFile(doc));
- }
-
- DebuggerSourceFile *DebuggerModule::ResolveSourceFile(ISymUnmanagedDocument *doc)
- {
- DebuggerSourceFile *file =
- (DebuggerSourceFile*)m_sourceFiles.GetBase((ULONG)doc);
-
- if (file == NULL)
- {
- file = new DebuggerSourceFile(this, doc);
- _ASSERTE(file != NULL);
-
- if (file != NULL)
- m_sourceFiles.AddBase(file);
- }
-
- return (file);
- }
-
- DebuggerFunction *DebuggerModule::ResolveFunction(mdMethodDef md,
- ICorDebugFunction *iFunction)
- {
- // Make sure we don't have obviously invalid arguments
- _ASSERTE((md != mdMethodDefNil) || (iFunction != NULL));
-
- // What will be returned
- DebuggerFunction *function;
-
- // Get a pointer to the DebuggerFunction object
- if (md != mdMethodDefNil)
- function = (DebuggerFunction *)m_functions.GetBase(md);
- else
- function = (DebuggerFunction *)m_functionsByIF.GetBase((ULONG)iFunction);
-
- // Has not been created yet
- if (function == NULL)
- {
- // Create a new object
- function = new DebuggerFunction(this, md, iFunction);
- _ASSERTE(function != NULL);
-
- // Out of memory
- if (function == NULL)
- {
- g_pShell->ReportError(E_OUTOFMEMORY);
- return NULL;
- }
-
- // Init the DebuggerFunction object
- HRESULT hr = function->Init();
-
- // Error check
- if (FAILED(hr))
- {
- g_pShell->ReportError(hr);
- delete function;
- return NULL;
- }
-
- // Add the DebuggerFunction object to the appropriate collection
- if (md != mdMethodDefNil)
- m_functions.AddBase(function);
- else
- m_functionsByIF.AddBase(function);
- }
-
- // Return DebuggerFunction pointer
- return (function);
- }
-
- DebuggerFunction *DebuggerModule::ResolveFunction(ISymUnmanagedMethod *method,
- ICorDebugFunction *iFunction)
- {
- HRESULT hr = S_OK;
-
- mdMethodDef tk;
-
- hr = method->GetToken(&tk);
-
- if (FAILED(hr))
- return NULL;
- else
- return ResolveFunction(tk, iFunction);
- }
-
- DebuggerModule *DebuggerModule::FromCorDebug(ICorDebugModule *module)
- {
- // Return the DebuggerModule object
- return (g_pShell->ResolveModule(module));
- }
-
-
- HRESULT DebuggerModule::LoadSourceFileNames (void)
- {
- HRESULT hr = S_OK;
- int iBucket;
-
- // Get all of the source files within this module.
- ULONG32 docCount;
- ISymUnmanagedDocument **allDocs;
-
- if (!m_pISymUnmanagedReader)
- return S_OK;
-
- // How many documents?
- hr = m_pISymUnmanagedReader->GetDocuments(0, &docCount, NULL);
-
- if (FAILED(hr))
- return hr;
-
- // Allocate space for the documents.
- allDocs = (ISymUnmanagedDocument**)_alloca(docCount * sizeof(ISymUnmanagedDocument*));
- _ASSERTE(allDocs != NULL);
-
- hr = m_pISymUnmanagedReader->GetDocuments(docCount, &docCount, allDocs);
-
- if (FAILED(hr))
- return hr;
-
- // Loop over the documents, setting up each's name and path
- // accordingly.
- for (long i = 0; i < docCount; i++)
- {
- WCHAR docName[256];
- ULONG32 s;
-
- hr = allDocs[i]->GetURL(256, &s, docName);
-
- if (FAILED(hr))
- break;
-
- // @todo: the rest of the code expects an ASCII name. Fix that
- // sometime soon.
- MAKE_ANSIPTR_FROMWIDE(docNameA, docName);
-
- int iLen;
- iLen = strlen(docNameA);
-
- if (iLen)
- {
- // strip the path and store just the lowercase file name
- CHAR rcFile[MAX_PATH];
- _splitpath(docNameA, NULL, NULL, rcFile, NULL);
-
- // make the file name lowercase
- int j=0;
- while (rcFile [j] != '\0')
- {
- rcFile[j] = tolower(rcFile[j]);
- j++;
- }
-
- // Based on the stripped file name, decide the bucket in
- // which it should go
- if (rcFile [0] < 'a')
- iBucket = 0;
- else if (rcFile [0] > 'z')
- iBucket = MAX_SF_BUCKETS - 1;
- else
- iBucket = (rcFile [0] - 'a') % MAX_SF_BUCKETS;
-
- // Allocate a new ModuleSourceFile object
- ModuleSourceFile *pmsf = new ModuleSourceFile;
-
- if (pmsf)
- {
- if (!pmsf->SetFullFileName(allDocs[i], docNameA))
- {
- hr = E_FAIL;
- break;
- }
-
- // Add this ModuleSourceFile object to the cache
- pmsf->SetNext (m_pModSourceFile [iBucket]);
- m_pModSourceFile [iBucket] = pmsf;
- }
- else
- {
- // out of memory
- hr = E_OUTOFMEMORY;
- break;
- }
- }
-
- RELEASE(allDocs[i]);
- }
-
- // Indicate that the module's source files have been cached
- if (SUCCEEDED (hr))
- m_fSFNamesLoaded = true;
-
- return hr;
- }
-
- HRESULT DebuggerModule::MatchStrippedFNameInModule
- (
- WCHAR *pstrFileName, // file name to look for (assumed to have been converted to lower case)
- WCHAR **ppstrMatchedNames, // returned array containing full paths of matched filenames
- ISymUnmanagedDocument **ppDocs, // returned aray containing documents for source file
- int *piCount // number of files which matched the given filename
- )
- {
- HRESULT hr;
-
- *piCount = 0;
- _ASSERTE (pstrFileName);
-
- // The filename length should be > 0
- if (!wcslen (pstrFileName))
- return (E_INVALIDARG);
-
- if (!m_fSFNamesLoaded)
- {
- if ((hr = LoadSourceFileNames ()) != S_OK)
- return hr;
- }
-
- hr = E_FAIL;
-
- // first, extract strip the path+file name down to just the "file.ext" name
- WCHAR rcFile[MAX_PATH];
- WCHAR rcExt[MAX_EXT];
-
- _wsplitpath(pstrFileName, NULL, NULL, rcFile, rcExt);
- wcscat(rcFile, rcExt);
-
- // get the bucket in which this file should be searched for
- int iBucketIndex;
-
- if (rcFile [0] < 'a')
- iBucketIndex = 0;
- else if (rcFile [0] > 'z')
- iBucketIndex = MAX_SF_BUCKETS - 1;
- else
- iBucketIndex = (rcFile [0] - 'a') % MAX_SF_BUCKETS;
-
- ModuleSourceFile *pmsf = m_pModSourceFile [iBucketIndex];
-
- // Search the whole list to find the files names which match
- while (pmsf)
- {
- WCHAR *pStrippedFileName = pmsf->GetStrippedFileName();
- WCHAR strTemp [MAX_PATH];
-
- // convert the name to lowercase before comparing
- wcscpy (strTemp, pStrippedFileName);
-
- int i=0;
- while (strTemp [i] != L'\0')
- {
- strTemp [i] = towlower (strTemp [i]);
- i++;
- }
-
-
- if (!wcscmp (strTemp, rcFile))
- {
- _ASSERTE (*piCount < MAX_FILE_MATCHES_PER_MODULE);
- // found a match
- ppstrMatchedNames [*piCount] = pmsf->GetFullFileName();
- ppDocs [*piCount] = pmsf->GetDocument();
- (*piCount)++;
- hr = S_OK;
- }
-
- pmsf = pmsf->GetNext();
- }
-
- return hr;
- }
-
-
- HRESULT DebuggerModule::MatchFullFileNameInModule (WCHAR *pstrFileName,
- ISymUnmanagedDocument **pDoc)
- {
-
- int iBucketIndex;
-
- HRESULT hr;
-
- _ASSERTE (pstrFileName);
-
- // The filename length should be > 0
- if (!wcslen (pstrFileName))
- return (E_INVALIDARG);
-
- if (!m_fSFNamesLoaded)
- {
- if ((hr = LoadSourceFileNames ()) != S_OK)
- return hr;
- }
-
- hr = E_FAIL; // assume we won't find it in this module.
-
- // first, extract strip the path+file name down to just the "file.ext" name
-
- WCHAR rcFile[MAX_PATH];
- WCHAR rcExt[MAX_EXT];
-
- _wsplitpath(pstrFileName, NULL, NULL, rcFile, rcExt);
- wcscat(rcFile, rcExt);
-
- // get the bucket in which this file should be searched for
- if (rcFile [0] < 'a')
- iBucketIndex = 0;
- else if (rcFile [0] > 'z')
- iBucketIndex = MAX_SF_BUCKETS - 1;
- else
- iBucketIndex = (rcFile [0] - 'a') % MAX_SF_BUCKETS;
-
- ModuleSourceFile *pmsf = m_pModSourceFile [iBucketIndex];
-
- // Search the whole list to find the files name which matches
- while (pmsf)
- {
- WCHAR *pFullFileName = pmsf->GetFullFileName();
-
- if (!wcscmp (pFullFileName, pstrFileName))
- {
- // found a match
- *pDoc = pmsf->GetDocument();
- hr = S_OK;
- break;
- }
-
- pmsf = pmsf->GetNext();
- }
-
- return hr;
- }
-
-
- void DebuggerModule::SetName (WCHAR *pszName)
- {
- if (pszName != NULL)
- {
- m_szName = new WCHAR [wcslen (pszName) + 1];
- if (m_szName != NULL)
- {
- wcscpy (m_szName, pszName);
- }
- }
- }
-
- //
- // Update the symbols for this module. Creates the syms if they aren't
- // already created.
- //
- HRESULT DebuggerModule::UpdateSymbols(IStream *pStream)
- {
- HRESULT hr = S_OK;
-
- // If we don't already have a reader, create one.
- if (m_pISymUnmanagedReader == NULL)
- {
- ISymUnmanagedBinder *pBinder = NULL;
-
- hr = CoCreateInstance(CLSID_CorSymBinder, NULL,
- CLSCTX_INPROC_SERVER,
- IID_ISymUnmanagedBinder,
- (void**)&pBinder);
-
- if (SUCCEEDED(hr))
- {
- hr = pBinder->GetReaderFromStream(m_pIMetaDataImport,
- pStream,
- &m_pISymUnmanagedReader);
-
- if (FAILED(hr))
- m_pISymUnmanagedReader = NULL;
-
- pBinder->Release();
- }
- }
- else
- {
- // We already have a reader, so just replace the symbols. We
- // replace instead of update because we are doing this only
- // for dynamic modules and the syms are cumulative.
- hr = m_pISymUnmanagedReader->ReplaceSymbolStore(NULL, pStream);
- }
-
- return hr;
- }
-
- void DebuggerShell::PrintGlobalVariable (mdFieldDef mdTok,
- WCHAR *wszName,
- DebuggerModule *dm)
- {
- ICorDebugModule *mod = dm->GetICorDebugModule();
- ICorDebugValue *val = NULL;
- HRESULT hr = S_OK;
-
- _ASSERTE( mod != NULL );
-
- hr = mod->GetGlobalVariableValue(mdTok, &val);
- if (FAILED(hr))
- return;
-
- this->PrintVariable(wszName,
- val,
- 4, //sure, sounds good
- TRUE);
-
- RELEASE(val);
-
- Write(L"\n");
- }
-
- #define PRINT_ALL 1
- #define MATCH_N_CHARS 2
- #define MATCH_ALL_CHARS 3
-
- BOOL DebuggerModule::PrintGlobalVariables (WCHAR *szSearchString,
- char *szModName,
- DebuggerModule *dm)
- {
- BOOL fWildCard = FALSE;
- int iMatchKind;
- int iLength = wcslen (szSearchString);
- char szSearchName [MAX_SYMBOL_NAME_LENGTH];
-
- BOOL fDone = FALSE;
- for (int i=0; i<iLength; i++)
- {
- if (szSearchString [i] == L'*')
- {
- fWildCard = TRUE;
- iLength = i;
- break;
- }
- }
-
- if (iLength==0)
- {
- // print all symbols
- iMatchKind = PRINT_ALL;
- }
- else
- {
- szSearchString [iLength] = L'\0';
- MAKE_UTF8PTR_FROMWIDE (szSearchName1, szSearchString);
-
- strcpy (szSearchName, szSearchName1);
-
- if (fWildCard)
- {
- // match 'iLength' characters only
- iMatchKind = MATCH_N_CHARS;
- }
- else
- {
- // match the whole string
- iMatchKind = MATCH_ALL_CHARS;
- }
- }
-
- // first, look for the global functions
- HCORENUM phEnum = 0;
- mdMethodDef rTokens[100];
- unsigned long count;
- HRESULT hr;
- MDUTF8CSTR name;
- MDUTF8STR u_name;
- MDUTF8STR szMDName;
- bool anythingPrinted = false;
-
- u_name = new char[256];
-
- do
- {
- hr = m_pIMetaDataImport->EnumFields(&phEnum, NULL, &rTokens[0], 100, &count);
-
- if (!SUCCEEDED(hr))
- {
- g_pShell->ReportError(hr);
- goto ErrExit;
- }
-
- for (i = 0; i < count; i++)
- {
- hr = m_pIMetaDataImport->GetNameFromToken(rTokens[i], &name);
-
- if (name == NULL)
- continue;
-
- MAKE_WIDEPTR_FROMUTF8( wszName, name );
-
- szMDName = (MDUTF8STR) name;
-
- if (iMatchKind == PRINT_ALL)
- {
- g_pShell->PrintGlobalVariable (rTokens[i],
- wszName,
- dm);
- anythingPrinted = true;
- }
- else
- {
- if (iMatchKind == MATCH_N_CHARS)
- {
- if (!strncmp (szMDName, szSearchName, iLength))
- {
- g_pShell->PrintGlobalVariable (rTokens[i],
- wszName,
- dm);
- anythingPrinted = true;
- }
- }
- else
- {
- if (!strcmp (szMDName, szSearchName))
- {
- g_pShell->PrintGlobalVariable (rTokens[i],
- wszName,
- dm);
- anythingPrinted = true;
- }
- }
- }
- }
- }
- while (count > 0);
-
- ErrExit:
- delete u_name;
-
- if (!anythingPrinted)
- return FALSE;
- return TRUE;
- }
-
- BOOL DebuggerModule::PrintMatchingSymbols (WCHAR *szSearchString, char *szModName)
- {
- BOOL fWildCard = FALSE;
- int iMatchKind;
- int iLength = wcslen (szSearchString);
- char szSearchName [MAX_SYMBOL_NAME_LENGTH];
-
- BOOL fDone = FALSE;
- for (int i=0; i<iLength; i++)
- {
- if (szSearchString [i] == L'*')
- {
- fWildCard = TRUE;
- iLength = i;
- break;
- }
- }
-
- if (iLength==0)
- {
- // print all symbols
- iMatchKind = PRINT_ALL;
- }
- else
- {
- szSearchString [iLength] = L'\0';
- MAKE_UTF8PTR_FROMWIDE (szSearchName1, szSearchString);
-
- strcpy (szSearchName, szSearchName1);
-
- if (fWildCard)
- {
- // match 'iLength' characters only
- iMatchKind = MATCH_N_CHARS;
- }
- else
- {
- // match the whole string
- iMatchKind = MATCH_ALL_CHARS;
- }
- }
-
- // first, look for the global functions
- HCORENUM phEnum = 0;
- mdMethodDef rTokens[100];
- mdTypeDef rClassTokens [100];
- unsigned long count;
- HRESULT hr;
- MDUTF8CSTR name;
- MDUTF8CSTR name1;
- MDUTF8STR u_name;
- MDUTF8STR szMDName;
- bool anythingPrinted = false;
-
- u_name = new char[256];
-
- do
- {
- hr = m_pIMetaDataImport->EnumMethods(&phEnum, NULL, &rTokens[0], 100, &count);
-
- if (!SUCCEEDED(hr))
- {
- g_pShell->ReportError(hr);
- goto ErrExit;
- }
-
- for (i = 0; i < count; i++)
- {
- hr = m_pIMetaDataImport->GetNameFromToken(rTokens[i], &name);
-
- if (name == NULL)
- continue;
-
- szMDName = (MDUTF8STR) name;
-
- if (iMatchKind == PRINT_ALL)
- {
- g_pShell->Write (L"%S!::%S\n", szModName, szMDName);
- anythingPrinted = true;
- }
- else
- {
- if (iMatchKind == MATCH_N_CHARS)
- {
- if (!strncmp (szMDName, szSearchName, iLength))
- {
- g_pShell->Write (L"%S!::%S\n", szModName, szMDName);
- anythingPrinted = true;
- }
- }
- else
- {
- if (!strcmp (szMDName, szSearchName))
- {
- g_pShell->Write (L"%S!::%S\n", szModName, szMDName);
- anythingPrinted = true;
- }
- }
- }
- }
- }
- while (count > 0);
-
- // now enumerate all the classes...
- phEnum = 0;
- do
- {
- hr = m_pIMetaDataImport->EnumTypeDefs (&phEnum, &rClassTokens[0], 100, &count);
-
- if (!SUCCEEDED(hr))
- {
- g_pShell->ReportError(hr);
- goto ErrExit;
- }
-
- for (i = 0; i < count; i++)
- {
- BOOL fMatchFound = FALSE;
- WCHAR wszClassName [MAX_SYMBOL_NAME_LENGTH];
- ULONG ulClassNameLen;
- CLASSVERSION version;
- DWORD dwTypeDefFlags;
- mdToken tkExtends;
-
- wszClassName [0] = L'\0';
-
- hr = m_pIMetaDataImport->GetTypeDefProps (rClassTokens [i],
- wszClassName,
- MAX_SYMBOL_NAME_LENGTH-1,
- &ulClassNameLen,
- &version,
- &dwTypeDefFlags,
- &tkExtends);
-
- if (wcslen (wszClassName) == 0)
- continue;
-
- MAKE_ANSIPTR_FROMWIDE (szMDClassName, wszClassName);
-
- if (iMatchKind == PRINT_ALL)
- {
- fMatchFound = TRUE;
- }
- else
- {
- if (iMatchKind == MATCH_N_CHARS)
- {
- if (!strncmp (szMDClassName, szSearchName, iLength))
- {
- fMatchFound = TRUE;
- }
- }
- else
- {
- if (!strcmp (szMDClassName, szSearchName))
- {
- fMatchFound = TRUE;
- }
- }
- }
-
-
- if (fMatchFound)
- {
- ULONG ulClassCount;
- HCORENUM phClassEnum = 0;
- do
- {
- ulClassCount = 0;
- hr = m_pIMetaDataImport->EnumMethods(&phClassEnum, rClassTokens [i], &rTokens[0], 100, &ulClassCount);
-
- if (!SUCCEEDED(hr))
- {
- g_pShell->ReportError(hr);
- goto ErrExit;
- }
-
- for (int j = 0; j < ulClassCount; j++)
- {
- name1 = NULL;
- hr = m_pIMetaDataImport->GetNameFromToken(rTokens[j], &name1);
-
- if (name1 == NULL)
- continue;
-
- szMDName = (MDUTF8STR)name1;
-
- g_pShell->Write (L"%S!%S::%S\n", szModName, szMDClassName, szMDName);
- anythingPrinted = true;
- }
- }
- while (ulClassCount > 0);
- }
- }
-
- }while (count > 0);
-
- ErrExit:
- delete u_name;
-
- if (!anythingPrinted)
- return FALSE;
- return TRUE;
- }
-
-
- /* ------------------------------------------------------------------------- *
- * DebuggerSourceFile
- * ------------------------------------------------------------------------- */
-
- DebuggerSourceFile::DebuggerSourceFile(DebuggerModule *module,
- ISymUnmanagedDocument *doc)
- : DebuggerBase((LONG)doc), m_module(module),
- m_allBlocksLoaded(false),
- m_totalLines(0), m_lineStarts(NULL),
- m_source(NULL), m_sourceTextLoaded(false),
- m_name(NULL), m_path(NULL),
- m_sourceNotFound(FALSE)
- {
- ULONG32 nameLen;
-
- // Get the length of the name first
- HRESULT hr = doc->GetURL(0, &nameLen, NULL);
-
- // Allocate space for the name
- m_name = new WCHAR[nameLen + 1];
-
- if (m_name)
- {
- // Now, copy the name for real.
- hr = doc->GetURL(nameLen + 1, &nameLen, m_name);
- }
- else
- hr = E_OUTOFMEMORY;
-
- // If unsuccessful, don't initialize the source name
- if (FAILED(hr))
- {
- g_pShell->ReportError(hr);
-
- if (m_name)
- delete [] m_name;
-
- m_name = NULL;
- }
- }
-
- DebuggerSourceFile::~DebuggerSourceFile()
- {
- delete [] m_source;
- delete [] m_lineStarts;
- delete [] m_path;
- delete [] m_name;
- }
-
- // LoadText loads the text of a source file and builds a table of pointers
- // to the start of each line.
- //
- // @todo: will probally want to return extended error information one day
- // instead of just true or false.
- //
- BOOL DebuggerSourceFile::LoadText(const WCHAR* path, bool bChangeOfName)
- {
- BOOLEAN fRetVal = FALSE;
- char *sourceA = NULL;
- int size = 0;
- WCHAR* ptr = NULL;
- unsigned int i = 0;
- int ilen = 0;
-
- if (m_sourceTextLoaded)
- return (TRUE);
-
- // Where to store fully qualified name
- char fullyQualifiedName[MAX_PATH];
-
- // Must convert to ANSI for Win9x users
- MAKE_ANSIPTR_FROMWIDE(pathA, path);
- _ASSERTE(pathA != NULL);
-
-
- HRESULT hr;
-
- // Let the shell see if it can resolve the source location.
- if ((hr = g_pShell->ResolveSourceFile(this, pathA, fullyQualifiedName, MAX_PATH, bChangeOfName)) != S_OK)
- {
- if (!m_sourceNotFound)
- {
- g_pShell->Write(L"\nError loading source file '%s': File not found\n", m_name);
- m_sourceNotFound = TRUE;
- }
-
- return (FALSE);
-
- }
-
-
- m_sourceNotFound = FALSE;
-
- // Read the source file into memory.
- HANDLE hFile = CreateFileA(fullyQualifiedName, GENERIC_READ,
- FILE_SHARE_READ, NULL, OPEN_EXISTING,
- FILE_ATTRIBUTE_NORMAL, NULL);
-
- if (hFile == INVALID_HANDLE_VALUE)
- {
- HRESULT hr = HRESULT_FROM_WIN32(GetLastError());
-
- // No luck, report error.
- g_pShell->ReportError(hr);
- return (FALSE);
- }
-
- DWORD sizeA = GetFileSize(hFile, NULL);
-
- if (sizeA == 0xFFFFFFFF)
- {
- g_pShell->ReportError(HRESULT_FROM_WIN32(GetLastError()));
- CloseHandle(hFile);
- return (FALSE);
- }
-
- sourceA = new char[ (sizeA * sizeof(char)) ];
- if (sourceA == NULL)
- {
- g_pShell->Write( L"Insufficient memory to load file '%s'\n",m_name );
- CloseHandle(hFile);
- return (FALSE);
- }
-
- DWORD sizeReadA;
- BOOL ret = ReadFile(hFile, (void*) sourceA, sizeA, &sizeReadA, NULL);
-
- CloseHandle(hFile);
-
- if ((ret == FALSE) || (sizeA != sizeReadA))
- {
- if (ret == FALSE)
- g_pShell->ReportError(HRESULT_FROM_WIN32(GetLastError()));
-
- goto LExit;
- }
-
- // Translate the source file into UNICODE
- size = MultiByteToWideChar(CP_ACP, 0, sourceA, sizeA, NULL, 0);
-
- m_source = new WCHAR[size+1];
- _ASSERTE(m_source != NULL);
-
- if (m_source == NULL)
- goto LExit;
-
- MultiByteToWideChar(CP_ACP, 0, sourceA, sizeA, m_source, size);
-
- // Null terminate the wide string array
- m_source [size] = L'\0';
-
- //
- // Figure out how many lines are in this file.
- //
- ptr = m_source;
- m_totalLines = 0;
-
- while (ptr < (m_source + size))
- {
- if (*ptr++ == L'\n')
- m_totalLines++;
- }
-
- // account for the fact that the last line of the
- // file may contain text. So number of lines needs
- // to be incremented if this is the case.
- if ((size > 0) && (*(ptr-1) != L'\n'))
- m_totalLines++;
-
- // Build an array to point to the beginning of each line of the file.
- // Chop up the file into separate strings while we're at it.
- if (m_totalLines == 0)
- goto LExit;
-
-
- m_lineStarts = new WCHAR*[m_totalLines];
- _ASSERTE(m_lineStarts != NULL);
-
- if (m_lineStarts == NULL)
- {
- delete m_source;
- goto LExit;
- }
-
- ptr = m_source;
- m_lineStarts[i++] = ptr;
-
- while (ptr < (m_source + size))
- {
- if (*ptr++ == '\n')
- {
- *(ptr - 1) = '\0';
-
- if ((ptr > m_source + 1) && (*(ptr - 2) == '\r'))
- *(ptr - 2) = '\0';
-
- if (i < m_totalLines)
- m_lineStarts[i++] = ptr;
- }
- }
-
- m_sourceTextLoaded = TRUE;
-
- ilen = MultiByteToWideChar(CP_ACP, 0, fullyQualifiedName, -1, NULL, 0);
- m_path = new WCHAR[ilen+1];
- if (m_path)
- MultiByteToWideChar(CP_ACP, 0, fullyQualifiedName, -1, m_path, ilen+1);
- fRetVal = (TRUE);
- LExit:
- if (sourceA != NULL )
- {
- delete [] sourceA;
- sourceA = NULL;
- }
-
- return fRetVal;
- }
-
- BOOL DebuggerSourceFile::ReloadText(const WCHAR *path, bool bChangeOfName)
- {
- m_sourceTextLoaded = FALSE;
-
- if (m_source != NULL)
- {
- delete m_source;
- m_source = NULL;
- }
-
- if (m_lineStarts != NULL)
- {
- delete m_lineStarts;
- m_lineStarts = NULL;
- }
-
- m_totalLines = 0;
-
- return (LoadText(path, bChangeOfName));
- }
-
- unsigned int DebuggerSourceFile::FindClosestLine(unsigned int line,
- bool silently)
- {
- HRESULT hr = S_OK;
-
- // Find and return the closest line in this document.
- ULONG32 closeLine;
- hr = GetDocument()->FindClosestLine(line, &closeLine);
-
- if (SUCCEEDED(hr))
- {
- // @TODO: This is a symbolstore failure. Bug 28393.
- if ((hr == S_FALSE) ||
- ((closeLine > (line + 3)) || (closeLine < (line - 3))))
- hr = E_FAIL;
- }
-
- if (SUCCEEDED(hr))
- return closeLine;
- else
- {
- if (!silently)
- g_pShell->Write(L"Warning: source line may not have code. "
- L"Breakpoint binding may fail.\n");
-
- return line;
- }
- }
-
- /* ------------------------------------------------------------------------- *
- * DebuggerFunction
- * ------------------------------------------------------------------------- */
-
- //
- // _skipTypeInSignature -- skip past a type in a given signature.
- // Returns the number of bytes used by the type in the signature.
- //
- static ULONG _skipTypeInSignature(PCCOR_SIGNATURE sig)
- {
- ULONG cb = 0;
- ULONG elementType;
-
- cb += CorSigUncompressData(&sig[cb], &elementType);
-
- if ((elementType == ELEMENT_TYPE_CLASS) ||
- (elementType == ELEMENT_TYPE_VALUECLASS))
- {
- // Skip over typeref.
- mdToken typeRef;
- cb += CorSigUncompressToken(&sig[cb], &typeRef);
- }
- else if ((elementType == ELEMENT_TYPE_PTR) ||
- (elementType == ELEMENT_TYPE_BYREF) ||
- (elementType == ELEMENT_TYPE_GENERICARRAY) ||
- (elementType == ELEMENT_TYPE_PINNED) ||
- (elementType == ELEMENT_TYPE_SZARRAY))
- {
- // Skip over extra embedded type.
- cb += _skipTypeInSignature(&sig[cb]);
- }
- else if ((elementType == ELEMENT_TYPE_ARRAY) ||
- (elementType == ELEMENT_TYPE_ARRAY))
- {
- // Skip over extra embedded type.
- cb += _skipTypeInSignature(&sig[cb]);
-
- // Skip over rank
- ULONG rank;
- cb += CorSigUncompressData(&sig[cb], &rank);
-
- if (rank > 0)
- {
- // how many sizes?
- ULONG sizes;
- cb += CorSigUncompressData(&sig[cb], &sizes);
-
- // read out all the sizes
- unsigned int i;
-
- for (i = 0; i < sizes; i++)
- {
- ULONG dimSize;
- cb += CorSigUncompressData(&sig[cb], &dimSize);
- }
-
- // how many lower bounds?
- ULONG lowers;
- cb += CorSigUncompressData(&sig[cb], &lowers);
-
- // read out all the lower bounds.
- for (i = 0; i < lowers; i++)
- {
- int lowerBound;
- cb += CorSigUncompressSignedInt(&sig[cb], &lowerBound);
- }
- }
- }
-
- return (cb);
- }
-
- //
- // Static, global byte used to represent a signature for a class. A pointer
- // to this is used as the signature for the "this" argument to methods
- //
- static const BYTE g_ObjectSignature = ELEMENT_TYPE_CLASS;
-
- //
- // DebuggerFunction
- //
- // @todo VC_HACK: the extra hash and the work to notice if the method def
- // token is nil is to support debugging VC_HACK programs.
- //
- DebuggerFunction::DebuggerFunction(DebuggerModule *m, mdMethodDef md,
- ICorDebugFunction *iFunction)
- : DebuggerBase(md), m_module(m), m_class(0), m_ifunction(iFunction),
- m_isStatic(false), m_allBlocksLoaded(false), m_allScopesLoaded(false),
- m_arguments(NULL), m_argCount(0), m_VCHack(FALSE),
- m_returnType(NULL), m_signature(NULL), m_name(NULL), m_className(NULL),
- m_namespaceName(NULL),
- m_ilCode(NULL), m_ilCodeSize(0), m_nativeCode(NULL), m_nativeCodeSize(0),
- m_symMethod(NULL), m_SPCount(0), m_SPOffsets(NULL), m_SPDocuments(NULL),
- m_SPLines(NULL)
- {
- if (md == mdMethodDefNil)
- {
- m_token = (ULONG) iFunction;
- iFunction->AddRef();
- m_VCHack = TRUE;
- }
- }
-
-
- //
- // Obtain & Cache sequence point information
- //
- HRESULT DebuggerFunction::CacheSequencePoints(void)
- {
- HRESULT hr = S_OK;
-
- if (m_SPCount)
- {
- if (m_SPOffsets != NULL)
- {
- delete [] m_SPOffsets;
- }
- if (m_SPDocuments != NULL)
- {
- delete [] m_SPDocuments;
- }
- if (m_SPLines != NULL)
- {
- delete [] m_SPLines;
- }
- }
-
- // Now, load up the sequence points for this function since we
- // know that we'll need them later.
- if (m_symMethod)
- {
- hr = m_symMethod->GetSequencePointCount(&m_SPCount);
-
- TESTANDRETURNHR(hr);
-
- if (m_SPCount)
- {
- m_SPOffsets = new ULONG32[m_SPCount];
-
- if (!m_SPOffsets)
- return E_OUTOFMEMORY;
-
- m_SPDocuments = new ISymUnmanagedDocument*[m_SPCount];
-
- if (!m_SPDocuments)
- return E_OUTOFMEMORY;
-
- m_SPLines = new ULONG32[m_SPCount];
-
- if (!m_SPCount)
- return E_OUTOFMEMORY;
-
- ULONG32 actualCount;
-
- hr = m_symMethod->GetSequencePoints(m_SPCount,
- &actualCount,
- m_SPOffsets,
- m_SPDocuments,
- m_SPLines,
- NULL,
- NULL,
- NULL);
-
- TESTANDRETURNHR(hr);
-
- _ASSERTE(actualCount == m_SPCount);
- }
- }
-
- return hr;
- }
-
- //
- // Initialize a DebuggerFunction object.
- //
- HRESULT DebuggerFunction::Init(void)
- {
- if (m_VCHack)
- return (S_OK);
-
- HRESULT hr = S_OK;
-
- m_nEditAndContinueLastSynched = g_pShell->m_cEditAndContinues;
-
- // Get the symbol reader method for this method.
- if (GetModule()->GetSymbolReader() != NULL)
- {
- hr = GetModule()->GetSymbolReader()->GetMethod(GetToken(), &m_symMethod);
-
- if (hr != S_OK)
- m_symMethod = NULL;
- }
- else
- m_symMethod = NULL;
-
- CacheSequencePoints();
-
- //
- // Get properties of the method.
- //
- mdTypeDef classToken = mdTypeDefNil;
- WCHAR methodName[BUF_SIZE];
- ULONG methodNameLength = 0;
- PCCOR_SIGNATURE sigBlob = NULL;
- ULONG sigBlobSize = 0;
- DWORD methodAttr = 0;
- ULONG cb = 0;
-
- hr = m_module->GetMetaData()->GetMethodProps(GetToken(),
- &classToken,
- methodName, 256,
- &methodNameLength,
- &methodAttr,
- &sigBlob,
- &sigBlobSize,
- NULL, NULL);
-
- TESTANDRETURNHR(hr);
-
- m_signature = sigBlob; //@todo - do we have to release this, or is
- // this a pointer into MD owned space?
- m_class = classToken;
- m_name = new WCHAR[methodNameLength];
- _ASSERTE(m_name != NULL);
-
- if (m_name == NULL)
- return (E_OUTOFMEMORY);
-
- memcpy(m_name, methodName, methodNameLength * sizeof(WCHAR));
-
- //
- // Get properites of this method's class. (Mostly for the class name.)
- //
- if (m_class != mdTypeDefNil)
- {
- WCHAR fullName[MAX_CLASS_NAME];
- ULONG fullNameSize = 0;
- WCHAR *Namespace;
- ULONG NamespaceSize=0;
- WCHAR *className;
- ULONG classNameSize = 0;
-
- hr = m_module->GetMetaData()->GetTypeDefProps(classToken,
- fullName, MAX_CLASS_NAME,
- &fullNameSize,
- NULL, NULL,
- NULL);
- TESTANDRETURNHR(hr);
-
- Namespace = fullName;
- className = wcsrchr(fullName, L'.');
- if (className)
- *className++ = 0;
- else
- {
- Namespace = L"";
- className = fullName;
- }
-
- NamespaceSize = wcslen(Namespace) + 1;
- classNameSize = wcslen(className) + 1;
-
- m_namespaceName = new WCHAR[NamespaceSize+1];
- _ASSERTE(m_namespaceName != NULL);
-
- if (m_namespaceName == NULL)
- return (E_OUTOFMEMORY);
-
- memcpy(m_namespaceName, Namespace, NamespaceSize * sizeof(WCHAR));
-
- if (wcslen(Namespace))
- wcscat (m_namespaceName, L".");
- else
- m_namespaceName[0] = L'\0';
-
-
- m_className = new WCHAR[classNameSize];
- _ASSERTE(m_className != NULL);
-
- if (m_className == NULL)
- return (E_OUTOFMEMORY);
-
- memcpy(m_className, className, classNameSize * sizeof(WCHAR));
- }
- else
- {
- m_className = new WCHAR[1];
- _ASSERTE(m_className != NULL);
-
- if (m_className == NULL)
- return (E_OUTOFMEMORY);
- m_className [0] = L'\0';
-
- m_namespaceName = new WCHAR[1];
- _ASSERTE(m_namespaceName != NULL);
-
- if (m_namespaceName == NULL)
- return (E_OUTOFMEMORY);
- m_namespaceName [0] = L'\0';
- }
-
- //
- // Make sure we have a method signature.
- //
- ULONG callConv;
- cb += CorSigUncompressData(&sigBlob[cb], &callConv);
- _ASSERTE(callConv != IMAGE_CEE_CS_CALLCONV_FIELD);
-
- //
- // Grab the argument count.
- //
- ULONG argCount;
- cb += CorSigUncompressData(&sigBlob[cb], &argCount);
- m_argCount = argCount;
-
- //
- // Have the return type point directly to the return type in the
- // method signature.
- //
- m_returnType = &sigBlob[cb];
-
- //
- // Skip past the return type.
- //
- cb += _skipTypeInSignature(&sigBlob[cb]);
-
- m_isStatic = (methodAttr & mdStatic) != 0;
-
- unsigned int i;
-
- if (!m_isStatic)
- m_argCount++;
-
- if (m_argCount)
- {
- m_arguments = new DebuggerVarInfo[m_argCount];
-
- if (m_arguments == NULL)
- {
- m_argCount = 0;
- return (S_OK);
- }
-
- if (!m_isStatic)
- {
- char *newName = new char[5];
- _ASSERTE(newName != NULL);
- strcpy(newName, "this");
- m_arguments[0].name = newName;
- m_arguments[0].sig = (PCCOR_SIGNATURE) &g_ObjectSignature; // never really used...
- m_arguments[0].varNumber = 0;
-
- i = 1;
- }
- else
- i = 0;
-
- for (; i < m_argCount; i++)
- {
- m_arguments[i].name = NULL;
- m_arguments[i].sig = &sigBlob[cb];
- m_arguments[i].varNumber = i;
-
- cb += _skipTypeInSignature(&sigBlob[cb]);
- }
- }
-
- hr = m_module->GetICorDebugModule()->GetFunctionFromToken(GetToken(),
- &m_ifunction);
-
- if( FAILED(hr) )
- return hr;
-
- // Now, load any argument names.
- if (m_argCount > 0)
- {
- HCORENUM paramEnum = NULL;
- bool fCloseEnum = false;
- IMetaDataImport *pIMI = m_module->GetMetaData();
-
- while (TRUE)
- {
- mdParamDef param[1];
- ULONG numParams = 0;
-
- hr = pIMI->EnumParams(¶mEnum,
- GetToken(),
- param, 1, &numParams);
-
- if (SUCCEEDED(hr) && (numParams == 0))
- {
- fCloseEnum = true;
- hr = S_OK;
- break;
- }
-
- if (FAILED(hr))
- break;
-
- fCloseEnum = true;
-
- WCHAR name[BUF_SIZE];
- ULONG nameLen;
- ULONG seq;
-
- hr = pIMI->GetParamProps(param[0], 0,
- &seq, name, BUF_SIZE, &nameLen,
- NULL, NULL, NULL, NULL);
-
- if (SUCCEEDED(hr))
- {
- char* newName = new char[nameLen];
- _ASSERTE(newName != NULL);
-
- unsigned int i;
-
- for (i = 0; i < nameLen; i++)
- newName[i] = name[i];
-
- if (m_isStatic)
- seq--;
-
- if (seq < m_argCount)
- m_arguments[seq].name = newName;
- else
- {
- g_pShell->Write(L"Superflous parameter name detected: "
- L"%s::%s Sequence=%d, name=%s\n",
- m_className, m_name, seq, name);
- delete [] newName;
- }
- }
- else
- break;
- }
-
- if (fCloseEnum)
- pIMI->CloseEnum(paramEnum);
-
- // Give any unnamed aguments names now...
- for (i = 0; i < m_argCount; i++)
- {
- if (m_arguments[i].name == NULL)
- {
- char *newName = new char[07];
- _ASSERTE(newName != NULL);
- sprintf(newName, "Arg%d", i);
- m_arguments[i].name = newName;
- }
- }
- }
-
- return (hr);
- }
-
-
- DebuggerFunction::~DebuggerFunction()
- {
-
- if (m_arguments != NULL)
- {
- unsigned int i;
-
- for (i = 0; i < m_argCount; i++)
- delete [] (char *) m_arguments[i].name;
-
- delete [] m_arguments;
- }
-
- delete m_nativeCode;
- delete m_ilCode;
- delete [] m_name;
- delete [] m_className;
- delete [] m_namespaceName;
-
- g_pShell->m_invalidCache = false;
-
- if (m_ifunction != NULL)
- RELEASE(m_ifunction);
-
- if (m_symMethod)
- {
- if (m_SPOffsets)
- delete [] m_SPOffsets;
-
- if (m_SPDocuments)
- {
- for (int i = 0; i < m_SPCount; i++)
- m_SPDocuments[i]->Release();
-
- delete [] m_SPDocuments;
- }
-
- if (m_SPLines)
- delete [] m_SPLines;
-
- RELEASE(m_symMethod);
- }
- }
-
- //
- // Find the lowest line number that corresponds to a given IP with the method.
- //
- HRESULT DebuggerFunction::FindLineFromIP(UINT_PTR ip,
- DebuggerSourceFile **pDoc,
- unsigned int *line)
- {
- HRESULT hr = S_FALSE;
-
- *pDoc = NULL;
- *line = 0;
-
- unsigned int i;
-
- // Make sure we've got the most recent copy....
- if (g_pShell->m_cEditAndContinues != m_nEditAndContinueLastSynched)
- {
- hr = CacheSequencePoints();
-
- if (FAILED( hr ) )
- return hr;
-
- m_nEditAndContinueLastSynched = g_pShell->m_cEditAndContinues;
- }
-
- // Only search if we have something to search over
- if (m_SPCount > 0)
- {
- // If ip is lower than the first ip...
- if (m_SPOffsets[0] <= ip)
- {
- // Find the first entry that corresponds to this ip.
- for (i = 0; i < m_SPCount; i++)
- if (m_SPOffsets[i] >= ip)
- break;
-
- // If not an exact match, then we're one too high.
- if (((i == m_SPCount) || (m_SPOffsets[i] != ip)) && (i > 0))
- i--;
-
- *line = m_SPLines[i];
- VERIFY(*pDoc = GetModule()->ResolveSourceFile(m_SPDocuments[i]));
-
- hr = S_OK;
- }
- }
-
- return hr;
- }
-
-
- //
- // Get the line stepping range for the given ip.
- //
-
- void DebuggerFunction::GetStepRangesFromIP(UINT_PTR ip,
- COR_DEBUG_STEP_RANGE **range,
- SIZE_T *rangeCount)
- {
- HRESULT hr;
- //
- // !!! Really, we should find _all_ source lines, not just one. (?)
- //
-
- DebuggerSourceFile *file = NULL;
- unsigned int line;
-
- *range = NULL;
- *rangeCount = 0;
-
- hr = FindLineFromIP(ip, &file, &line);
-
- if (FAILED(hr))
- {
- g_pShell->ReportError(hr);
- return;
- }
-
- if (file == NULL || !file->LoadText(g_pShell->m_currentSourcesPath, false))
- return;
-
- ULONG32 *rangeArray = NULL;
- ULONG32 rangeArraySize = 0;
-
- // How many ranges are there?
- if (m_symMethod)
- {
- hr = m_symMethod->GetRanges(file->GetDocument(),
- line, 0,
- 0, &rangeArraySize, NULL);
-
- if (FAILED(hr))
- {
- g_pShell->ReportError(hr);
- return;
- }
- }
-
- if (rangeArraySize > 0)
- {
- // Make room and get the ranges.
- rangeArray = (ULONG32*)_alloca(sizeof(ULONG32) * rangeArraySize);
- _ASSERTE(rangeArray != NULL);
-
- hr = m_symMethod->GetRanges(file->GetDocument(),
- line, 0,
- rangeArraySize,
- &rangeArraySize,
- rangeArray);
-
- if (FAILED(hr))
- {
- g_pShell->ReportError(hr);
- return;
- }
-
- // lineRangeCount should be a reasonable approximation of
- // memory to allocate.
- *range = new COR_DEBUG_STEP_RANGE[rangeArraySize / 2];
- _ASSERTE(*range != NULL);
-
- COR_DEBUG_STEP_RANGE *r = *range;
-
- for (int i = 0; i < rangeArraySize; i += 2)
- {
- r->startOffset = rangeArray[i];
- r->endOffset = rangeArray[i+1];
-
- r++;
- }
- }
- else
- *range = NULL;
-
- *rangeCount = rangeArraySize / 2;
- }
-
-
- //
- // Given a scope, determine how many local vars are "active" at the given
- // line number. The count includes any locals that are active in scopes
- // that are children of the given scope.
- //
- void DebuggerFunction::CountActiveLocalVars(ISymUnmanagedScope* head,
- unsigned int ip,
- unsigned int* varCount)
- {
- if (head != NULL)
- {
- ULONG32 startOffset, endOffset;
-
- HRESULT hr = head->GetStartOffset(&startOffset);
- _ASSERTE(SUCCEEDED(hr));
- hr = head->GetEndOffset(&endOffset);
- _ASSERTE(SUCCEEDED(hr));
-
- if ((ip >= startOffset) && (ip <= endOffset))
- {
- ULONG32 childCount;
-
- // How many children?
- hr = head->GetChildren(0, &childCount, NULL);
-
- if (FAILED(hr))
- {
- g_pShell->ReportError(hr);
- return;
- }
-
- if (childCount > 0)
- {
- // Make room for the children
- ISymUnmanagedScope **children =
- (ISymUnmanagedScope**)_alloca(sizeof(ISymUnmanagedScope*) * childCount);
- _ASSERTE(children != NULL);
-
- // Get the children
- hr = head->GetChildren(childCount, &childCount, children);
-
- if (FAILED(hr))
- {
- g_pShell->ReportError(hr);
- return;
- }
-
- for (int i = 0; i < childCount; i++)
- {
- CountActiveLocalVars(children[i], ip, varCount);
- RELEASE(children[i]);
- }
- }
-
- ULONG32 vc;
- hr = head->GetLocalCount(&vc);
- _ASSERTE(SUCCEEDED(hr));
-
- *varCount += vc;
- }
- }
- }
-
-
- //
- // Given a scope and an array of DebuggerVarInfo pointers, fill up the array
- // with pointers to every "active" local variable within the scope, including
- // any active locals in child scopes. The size of the varPtrs array is
- // passed in as varCount and is used for bounds checking.
- //
- void DebuggerFunction::FillActiveLocalVars(ISymUnmanagedScope* head,
- unsigned int ip,
- unsigned int varCount,
- unsigned int* currentVar,
- DebuggerVariable* varPtrs)
- {
- if (head != NULL)
- {
- ULONG32 startOffset, endOffset;
-
- HRESULT hr = head->GetStartOffset(&startOffset);
- _ASSERTE(SUCCEEDED(hr));
- hr = head->GetEndOffset(&endOffset);
- _ASSERTE(SUCCEEDED(hr));
-
- if ((ip >= startOffset) && (ip <= endOffset))
- {
- ULONG32 childCount;
-
- // How many children?
- hr = head->GetChildren(0, &childCount, NULL);
-
- if (FAILED(hr))
- {
- g_pShell->ReportError(hr);
- return;
- }
-
- if (childCount > 0)
- {
- // Make room for the children
- ISymUnmanagedScope **children =
- (ISymUnmanagedScope**)_alloca(sizeof(ISymUnmanagedScope*) * childCount);
- _ASSERTE(children != NULL);
-
- // Get the children
- hr = head->GetChildren(childCount, &childCount, children);
-
- if (FAILED(hr))
- {
- g_pShell->ReportError(hr);
- return;
- }
-
- for (int i = 0; i < childCount; i++)
- {
- FillActiveLocalVars(children[i], ip, varCount,
- currentVar, varPtrs);
- RELEASE(children[i]);
- }
- }
-
- // Fill in any locals on this scope.
- ULONG32 localCount;
-
- // How many locals?
- hr = head->GetLocalCount(&localCount);
-
- if (FAILED(hr))
- {
- g_pShell->ReportError(hr);
- return;
- }
-
- if (localCount > 0)
- {
- // Make room for the localc
- ISymUnmanagedVariable **locals =
- (ISymUnmanagedVariable**)_alloca(sizeof(ISymUnmanagedVariable*) *
- localCount);
- _ASSERTE(locals != NULL);
-
- hr = head->GetLocals(localCount, &localCount, locals);
-
- if (FAILED(hr))
- {
- g_pShell->ReportError(hr);
- return;
- }
-
- for (int i = 0; i < localCount; i++)
- {
- _ASSERTE(*currentVar < varCount);
-
- // Get the size of the name.
- ULONG32 nameSize;
-
- hr = locals[i]->GetName(0, &nameSize, NULL);
-
- if (FAILED(hr))
- {
- g_pShell->ReportError(hr);
- return;
- }
-
- // Allocate space for the name.
- varPtrs[*currentVar].m_name = new WCHAR[nameSize + 1];
-
- if (varPtrs[*currentVar].m_name == NULL)
- {
- g_pShell->ReportError(E_OUTOFMEMORY);
- return;
- }
-
- // Get the name.
- hr = locals[i]->GetName(nameSize + 1, &nameSize,
- varPtrs[*currentVar].m_name);
-
- if (FAILED(hr))
- {
- g_pShell->ReportError(hr);
- return;
- }
-
- #ifdef _DEBUG
- ULONG32 addrKind;
- hr = locals[i]->GetAddressKind(&addrKind);
- _ASSERTE(addrKind == ADDR_IL_OFFSET);
- #endif
-
- hr = locals[i]->GetAddressField1(&(varPtrs[*currentVar].m_varNumber));
-
- if (FAILED(hr))
- {
- g_pShell->ReportError(hr);
- return;
- }
-
- (*currentVar)++;
- }
- }
- }
- }
- }
-
-
- //
- // Build a list of the active local variables within a method at a given IP.
- //
- bool DebuggerFunction::GetActiveLocalVars(UINT_PTR ip,
- DebuggerVariable** vars,
- unsigned int* count)
- {
- HRESULT hr = S_OK;
-
- *vars = NULL;
- *count = 0;
-
- // Grab the root scope for this method.
- ISymUnmanagedScope *rootScope = NULL;
-
- if (m_symMethod)
- {
- hr = m_symMethod->GetRootScope(&rootScope);
-
- if (FAILED(hr))
- {
- g_pShell->ReportError(hr);
- return false;
- }
- }
-
- // No work to do if there is no scope info for this method!
- if (!rootScope)
- return false;
-
- // Count the active locals.
- unsigned int localCount = 0;
-
- CountActiveLocalVars(rootScope, ip, &localCount);
-
- // No work to do if there aren't any locals in scope.
- if (localCount == 0)
- {
- rootScope->Release();
- return true;
- }
-
- // Allocate and fillup a list of DebuggerVariable pointers to
- // each variable.
- DebuggerVariable *varPtrs = new DebuggerVariable[localCount];
- _ASSERTE(varPtrs != NULL);
-
- if (varPtrs != NULL)
- {
- unsigned int currentVar = 0;
-
- FillActiveLocalVars(rootScope, ip, localCount,
- ¤tVar, varPtrs);
- }
- else
- localCount = 0;
-
- *vars = varPtrs;
- *count = localCount;
-
- rootScope->Release();
-
- return true;
- }
-
- DebuggerFunction *DebuggerFunction::FromCorDebug(ICorDebugFunction *function)
- {
- mdMethodDef md;
- HRESULT hr;
-
- // Get the method def token for function
- hr = function->GetToken(&md);
-
- // Error check
- if (FAILED(hr))
- {
- g_pShell->ReportError(hr);
- return NULL;
- }
-
- // Now get the module interface, so we can get a pointer to the CorDbg
- // DebuggerModule object
- ICorDebugModule *imodule;
- hr = function->GetModule(&imodule);
-
- // Error check
- if (FAILED(hr))
- {
- g_pShell->ReportError(hr);
- return NULL;
- }
-
- // Get a pointer to the CorDbg module
- DebuggerModule *m = DebuggerModule::FromCorDebug(imodule);
- _ASSERTE(m); // should never fail
-
- // Release the interface
- imodule->Release();
-
- // Use the debugger module to resolve the function to a DebuggerFunction ptr
- return (m->ResolveFunction(md, function));
- }
-
- HRESULT DebuggerFunction::LoadCode(BOOL native)
- {
- _ASSERTE( g_pShell != NULL );
- if (native)
- {
- // if (m_nativeCode != NULL && !g_pShell->m_invalidCache )
- // return (S_OK);
-
- // if( g_pShell->m_invalidCache )
- // { //@todo: is this safe?
- // delete m_nativeCode;
- // }
-
- ICorDebugCode *icode;
- HRESULT hr = m_ifunction->GetNativeCode(&icode);
-
- if (FAILED(hr) && hr != CORDBG_E_CODE_NOT_AVAILABLE)
- return (hr);
-
- ULONG32 size;
- icode->GetSize(&size);
-
- m_nativeCode = new BYTE [size];
- _ASSERTE(m_nativeCode != NULL);
- m_nativeCodeSize = size;
-
- if (m_nativeCode == NULL)
- return (E_OUTOFMEMORY);
-
- hr = icode->GetCode(0, size, size,
- m_nativeCode, &m_nativeCodeSize);
- if (FAILED(hr))
- return (hr);
-
- icode->Release();
-
- if (FAILED(hr))
- {
- delete m_nativeCode;
- return (hr);
- }
-
- return (S_OK);
- }
- else
- {
- if (m_ilCode != NULL)
- return (S_OK);
-
- ICorDebugCode *icode;
- HRESULT hr = m_ifunction->GetILCode(&icode);
- if (FAILED(hr))
- return (hr);
-
- ULONG32 size;
- icode->GetSize(&size);
-
- m_ilCode = new BYTE [size];
- m_ilCodeSize = size;
-
- if (m_ilCode == NULL)
- return (E_OUTOFMEMORY);
-
- hr = icode->GetCode(0, size, size,
- m_ilCode, &m_ilCodeSize);
- if (FAILED(hr))
- return (hr);
-
- icode->Release();
-
- if (FAILED(hr))
- {
- delete m_ilCode;
- return (FALSE);
- }
-
- return (S_OK);
- }
- }
-
- BOOL DebuggerFunction::ValidateInstruction(BOOL native, SIZE_T offset)
- {
- if (FAILED(LoadCode(native)))
- return (FALSE);
-
- if (native)
- {
- if (offset >= m_nativeCodeSize)
- return (false);
- }
- else
- {
- if (offset >= m_ilCodeSize)
- return (false);
- }
-
- SIZE_T walk = 0;
-
- #ifdef _INTERNAL_DEBUG_SUPPORT_
- while (walk < offset)
- walk = WalkInstruction(native, walk);
- #endif
-
- return (walk == offset);
- }
-
- /* ------------------------------------------------------------------------- *
- * DebuggerCodeBreakpoint
- * ------------------------------------------------------------------------- */
-
- DebuggerCodeBreakpoint::DebuggerCodeBreakpoint(int breakpointID,
- DebuggerModule *module,
- DebuggerFunction *function,
- SIZE_T offset, BOOL il,
- DWORD threadID)
- : m_id(breakpointID), m_module(module), m_function(function),
- m_offset(offset), m_il(il), m_threadID(threadID),
- m_ibreakpoint(NULL), m_parent(NULL)
- {
- m_next = m_module->m_breakpoints;
- m_module->m_breakpoints = this;
- m_id = breakpointID;
- }
-
- DebuggerCodeBreakpoint::DebuggerCodeBreakpoint(
- int breakpointID, DebuggerModule *module,
- DebuggerSourceCodeBreakpoint *parent,
- DebuggerFunction *function, SIZE_T offset, BOOL il,
- DWORD threadID)
- : m_id(breakpointID), m_module(module), m_function(function),
- m_offset(offset), m_il(il),
- m_threadID(threadID),
- m_ibreakpoint(NULL), m_parent(parent)
- {
- m_next = parent->m_breakpoints;
- parent->m_breakpoints = this;
- m_id = parent->m_id;
- }
-
- DebuggerCodeBreakpoint::~DebuggerCodeBreakpoint()
- {
- DebuggerCodeBreakpoint **next;
-
- //
- // Remove either global list or parent list
- //
-
- if (m_parent == NULL)
- next = &m_module->m_breakpoints;
- else
- next = &m_parent->m_breakpoints;
-
- while ((*next) != this)
- next = &((*next)->m_next);
-
- *next = (*next)->m_next;
-
- //
- // Destroy the cor breakpoint
- //
-
- if (m_ibreakpoint != NULL)
- {
- m_ibreakpoint->Activate(FALSE);
- m_ibreakpoint->Release();
- }
- }
-
- bool DebuggerCodeBreakpoint::Activate()
- {
- if (m_ibreakpoint == NULL && m_function != NULL)
- {
- ICorDebugCode *icode;
-
- HRESULT hr;
-
- if (m_il)
- hr = m_function->m_ifunction->GetILCode(&icode);
- else
- hr = m_function->m_ifunction->GetNativeCode(&icode);
-
- if (SUCCEEDED(hr) || hr == CORDBG_E_CODE_NOT_AVAILABLE)
- hr = icode->CreateBreakpoint(m_offset, &m_ibreakpoint);
- }
-
- if (m_ibreakpoint != NULL)
- {
- m_ibreakpoint->Activate(TRUE);
- return (true);
- }
- else
- return (false);
- }
-
- void DebuggerCodeBreakpoint::Deactivate()
- {
- if (m_ibreakpoint != NULL)
- {
- m_ibreakpoint->Activate(FALSE);
- m_ibreakpoint->Release();
- m_ibreakpoint = NULL;
- }
- }
-
- bool DebuggerCodeBreakpoint::Match(ICorDebugBreakpoint *ibreakpoint)
- {
- return (ibreakpoint == m_ibreakpoint);
- }
-
- void DebuggerCodeBreakpoint::Print()
- {
- g_pShell->Write(L"%s+0x%x(%s) [%sactive]",
- m_function->GetName(), m_offset,
- m_il ? L"il" : L"native",
- m_ibreakpoint == NULL ? L"in" : L"");
- }
-
- DebuggerSourceCodeBreakpoint::DebuggerSourceCodeBreakpoint(
- int breakpointID,
- DebuggerSourceFile *file,
- SIZE_T lineNumber,
- DWORD threadID)
- : DebuggerCodeBreakpoint(breakpointID, file->m_module, NULL,
- 0, FALSE, threadID),
- m_file(file), m_lineNumber(lineNumber), m_breakpoints(NULL)
- {
- DebuggerModule *m = file->m_module;
-
- // GetMethodFromDocumentPosition to get an ISymUnmanagedMethod from this doc.
- ISymUnmanagedMethod *pSymMethod;
-
- HRESULT hr = m->GetSymbolReader()->GetMethodFromDocumentPosition(
- file->GetDocument(),
- lineNumber, 0,
- &pSymMethod);
-
- if (FAILED(hr))
- {
- g_pShell->Write(L"Failed to find method to match source line. "
- L"Unable to set breakpoint.\n");
- g_pShell->ReportError(hr);
- return;
- }
-
- // Make a regular breakpoint a the start of each line range.
- ULONG32 *rangeArray = NULL;
- ULONG32 rangeArraySize = 0;
-
- // How many ranges are there?
- hr = pSymMethod->GetRanges(file->GetDocument(),
- lineNumber, 0,
- 0, &rangeArraySize, NULL);
-
- if (FAILED(hr))
- {
- g_pShell->ReportError(hr);
- return;
- }
-
- if (rangeArraySize > 0)
- {
- // Make room and get the ranges.
- rangeArray = (ULONG32*)_alloca(sizeof(ULONG32) * rangeArraySize);
- _ASSERTE(rangeArray != NULL);
-
- hr = pSymMethod->GetRanges(file->GetDocument(),
- lineNumber, 0,
- rangeArraySize,
- &rangeArraySize,
- rangeArray);
-
- if (FAILED(hr))
- {
- g_pShell->ReportError(hr);
- return;
- }
-
- DebuggerFunction *f = m_function = m->ResolveFunction(pSymMethod, NULL);
-
- if (rangeArraySize == 2)
- {
- m_offset = rangeArray[0];
- m_il = TRUE;
- }
- else
- {
- for (int i = 0; i < rangeArraySize; i += 2)
- {
- if (i > 0 && (rangeArray [i-1] == rangeArray [i]))
- continue;
-
- new DebuggerCodeBreakpoint(breakpointID, file->m_module,
- this, f, rangeArray[i], TRUE,
- m_threadID);
- }
- }
- }
- }
-
- DebuggerSourceCodeBreakpoint::~DebuggerSourceCodeBreakpoint()
- {
- while (m_breakpoints != NULL)
- delete m_breakpoints;
- }
-
- bool DebuggerSourceCodeBreakpoint::Activate()
- {
- bool result = true;
-
- DebuggerCodeBreakpoint::Activate();
-
- DebuggerCodeBreakpoint *b = m_breakpoints;
-
- while (b != NULL)
- {
- result = b->Activate() && result;
- b = b->m_next;
- }
-
- return (result);
- }
-
- void DebuggerSourceCodeBreakpoint::Deactivate()
- {
- DebuggerCodeBreakpoint::Deactivate();
-
- DebuggerCodeBreakpoint *b = m_breakpoints;
-
- while (b != NULL)
- {
- b->Deactivate();
- b = b->m_next;
- }
- }
-
- bool DebuggerSourceCodeBreakpoint::Match(ICorDebugBreakpoint *ibreakpoint)
- {
- if (ibreakpoint == m_ibreakpoint)
- return (true);
-
- DebuggerCodeBreakpoint *bp = m_breakpoints;
- while (bp != NULL)
- {
- if (bp->m_ibreakpoint == ibreakpoint)
- return (true);
- bp = bp->m_next;
- }
-
- return (false);
- }
-
- void DebuggerSourceCodeBreakpoint::Print()
- {
- DebuggerCodeBreakpoint *bp = m_breakpoints;
-
- if (bp == NULL)
- DebuggerCodeBreakpoint::Print();
- else
- while (bp != NULL)
- {
- bp->Print();
- bp = bp->m_next;
- }
- }
-
- /* ------------------------------------------------------------------------- *
- * StepperHashTable class
- * ------------------------------------------------------------------------- */
-
-
- HRESULT StepperHashTable::Initialize()
- {
- HRESULT hr = NewInit(m_iBuckets,
- sizeof(StepperHashEntry), 0xffff);
- if (FAILED(hr))
- return (hr);
-
- m_initialized = true;
- return S_OK;
- }
-
-
- HRESULT StepperHashTable::AddStepper(ICorDebugStepper *pStepper)
- {
- if (!m_initialized)
- {
- HRESULT hr = NewInit(m_iBuckets,
- sizeof(StepperHashEntry), 0xffff);
- if (FAILED(hr))
- return (hr);
-
- m_initialized = true;
- }
-
- StepperHashEntry *entry = (StepperHashEntry *) Add(HASH(pStepper));
-
- if (entry == NULL)
- return (E_FAIL);
- else
- entry->pStepper = pStepper;
-
- pStepper->AddRef(); //don't want this to disappear from under
- //the table's feet
-
- return (S_OK);
- }
-
- bool StepperHashTable::IsStepperPresent(ICorDebugStepper *pStepper)
- {
- if (!m_initialized)
- return false;
-
- StepperHashEntry *entry
- = (StepperHashEntry *) Find(HASH(pStepper), KEY(pStepper));
- if (entry == NULL)
- return false;
- else
- return true;
- }
-
- BOOL StepperHashTable::RemoveStepper(ICorDebugStepper *pStepper)
- {
- if (!m_initialized)
- return (FALSE);
-
- StepperHashEntry *entry
- = (StepperHashEntry *) Find(HASH(pStepper), KEY(pStepper));
-
- if (entry == NULL)
- return (FALSE);
-
- Delete(HASH(pStepper), (HASHENTRY *) entry);
-
- RELEASE(pStepper);
-
- return (TRUE);
- }
-
- void StepperHashTable::ReleaseAll()
- {
- if (!m_initialized)
- return;
-
- HASHFIND find;
- ICorDebugStepper *pStepper = NULL;
-
- pStepper = FindFirst(&find);
- while( pStepper != NULL)
- {
- RELEASE( pStepper );
- RemoveStepper( pStepper );
-
- pStepper = FindNext(&find);
- }
-
- Clear();
- }
-
- ICorDebugStepper *StepperHashTable::FindFirst(HASHFIND *find)
- {
- if (!m_initialized)
- return NULL;
-
- StepperHashEntry *entry = (StepperHashEntry *) FindFirstEntry(find);
- if (entry == NULL)
- return NULL;
- else
- return entry->pStepper;
- }
-
- ICorDebugStepper *StepperHashTable::FindNext(HASHFIND *find)
- {
- if (!m_initialized)
- return NULL;
-
- StepperHashEntry *entry = (StepperHashEntry *) FindNextEntry(find);
- if (entry == NULL)
- return NULL;
- else
- return entry->pStepper;
- }
-
-