/*++ Copyright (c) 1995 Microsoft Corporation Module Name: vsym.c Abstract: This function implements virtual symbols that can be added by the caller. Author: Pat Styles (patst) 5-June-2001 Environment: User Mode --*/ #include "private.h" #include "symbols.h" #include "globals.h" int __cdecl vsCompareAddrs( const void *one, const void *two ) { PVIRTUAL_SYMBOL vs1 = (PVIRTUAL_SYMBOL)one; PVIRTUAL_SYMBOL vs2 = (PVIRTUAL_SYMBOL)two; if (vs2->addr > vs1->addr) return -1; if (vs1->addr > vs2->addr) return 1; return 0; } BOOL vsAddSymbol( PMODULE_ENTRY mi, PCSTR name, DWORD64 addr, DWORD size ) { PVIRTUAL_SYMBOL vs; DWORD i; // look for another symbol at the same address vs = vsGetSymbol(mi, NULL, addr); if (vs) { SetLastError(ERROR_ALREADY_EXISTS); return false; } // look for an empty slot in the already existing list vs = vsBlankSymbol(mi); // not found: allow a new list or realloc to new size if (!vs) { i = mi->cvs + 1; if (!mi->vs) { assert(mi->cvs == 0); vs = (PVIRTUAL_SYMBOL)MemAlloc(sizeof(VIRTUAL_SYMBOL)); } else { assert(mi->cvs); vs = (PVIRTUAL_SYMBOL)MemReAlloc(mi->vs, i * sizeof(VIRTUAL_SYMBOL)); } if (!vs) { SetLastError(ERROR_NOT_ENOUGH_MEMORY); return false; } // reset the pointer and increment the count mi->vs = vs; vs = mi->vs + mi->cvs; mi->cvs++; } // copy in the new symbol CopyStrArray(vs->name, name); vs->addr = addr; vs->size = size; qsort(mi->vs, mi->cvs, sizeof(VIRTUAL_SYMBOL), vsCompareAddrs); mi->SymLoadError = SYMLOAD_OK; return true; } BOOL vsMatchSymbol( PVIRTUAL_SYMBOL vs, PCSTR name, DWORD64 addr ) { // Look for a mismatch in either name or addr. if (name && *name && strcmp(vs->name, name)) return false; if (addr && vs->addr != addr) return false; // When passing a null name and addr, we are looking // for a blank entry. Check if addr is zero. if (!name && !addr && vs->addr) return false; // hit! return true; } PVIRTUAL_SYMBOL vsGetSymbol( PMODULE_ENTRY mi, PCSTR name, DWORD64 addr ) { PVIRTUAL_SYMBOL vs; DWORD i; for (vs = mi->vs, i = 0; i < mi->cvs; vs++, i++) { if (vsMatchSymbol(vs, name, addr)) return vs; } return NULL; } BOOL vsDeleteSymbol( PMODULE_ENTRY mi, PCSTR name, DWORD64 addr ) { PVIRTUAL_SYMBOL vs; DWORD i; // look for an empty slot in the already existing list vs = NULL; for (vs = mi->vs, i = 0; i < mi->cvs; vs++, i++) { if (vsMatchSymbol(vs, name, addr)) { vs->addr = 0; return true; } } SetLastError(ERROR_NOT_FOUND); return false; } BOOL vsDumpSymbols( PMODULE_ENTRY mi ) // for debugging... { PVIRTUAL_SYMBOL vs; DWORD i; if (!mi->vs) return false; for (vs = mi->vs, i = 0; i < mi->cvs; vs++, i++) { if (vs->addr) dtrace("%s %I64lx\n", vs->name, vs->addr); } return true; } BOOL vsFillSymbolInfo( PSYMBOL_INFO si, PMODULE_ENTRY mi, PVIRTUAL_SYMBOL vs ) { DWORD dw; dw = si->MaxNameLen; ZeroMemory(si, sizeof(SYMBOL_INFO)); si->MaxNameLen = dw; CopyString(si->Name, vs->name, si->MaxNameLen); si->ModBase = mi->BaseOfDll; si->Address = vs->addr; si->Size = vs->size; si->Flags = SYMFLAG_VIRTUAL; return true; } BOOL vsGetSymbols( IN PPROCESS_ENTRY pe, IN PMODULE_ENTRY mi, IN PCSTR mask, IN DWORD64 addr, IN PROC callback, IN PVOID context, IN BOOL use64, IN BOOL unicode ) { PVIRTUAL_SYMBOL vs; DWORD i; BOOL fCase; BOOL rc; if (!mi->vs) return callback ? true : false; fCase = option(SYMOPT_CASE_INSENSITIVE) ? false : true; for (vs = mi->vs, i = 0; i < mi->cvs; vs++, i++) { if (mask && *mask && strcmpre(vs->name, mask, fCase)) continue; if (addr && (vs->addr != addr)) continue; vsFillSymbolInfo(&mi->vssi, mi, vs); if (!callback) return true; rc = DoEnumCallback(pe, &mi->vssi, mi->vssi.Size, callback, context, use64, unicode); if (!rc) { mi->code = ERROR_CANCELLED; return false; } } return callback ? true : false; } PSYMBOL_INFO vsFindSymbolByName( PPROCESS_ENTRY pe, PMODULE_ENTRY mi, LPSTR SymName ) { if (!vsGetSymbols(pe, mi, SymName, 0, NULL, NULL, 0, 0)) return NULL; if (!mi) mi = pe->ipmi; return &mi->vssi; } PSYMBOL_INFO vsGetSymNextPrev( PMODULE_ENTRY mi, DWORD64 addr, BOOL direction ) { PVIRTUAL_SYMBOL vs; PVIRTUAL_SYMBOL vsprev; DWORD i; // no entries, bail if (!mi->cvs) return NULL; // walk to the entry with a higher address vsprev = NULL; for (vs = mi->vs, i = 0; i < mi->cvs; vs++, i++) { if (vs->addr < addr) vsprev = vs; if (vs->addr > addr) break; } if (direction < 0) vs = vsprev; else if (i == mi->cvs) return NULL; if (!vs) return NULL; vsFillSymbolInfo(&mi->vssi, mi, vs); return &mi->vssi; } PSYMBOL_INFO vsGetSymFromAddr( PMODULE_ENTRY mi, DWORD64 addr, PDWORD64 disp ) { PVIRTUAL_SYMBOL vs; DWORD i; // find the entry with a higher address for (vs = mi->vs, i = 0; i < mi->cvs; vs++, i++) { if (vs->addr > addr) break; } // no hit, bail if (!i) return NULL; // rewind back to the hit. // If the symbol has a size, make sure we're within the limits. vs--; if (vs->size && (vs->addr + vs->size) < addr) return NULL; // bullseye! vsFillSymbolInfo(&mi->vssi, mi, vs); if (disp) *disp = addr - mi->vssi.Address; return &mi->vssi; } PSYMBOL_ENTRY vsGetSymEntryFromAddr( PMODULE_ENTRY mi, DWORD64 addr, PDWORD64 disp ) { PSYMBOL_INFO si; si = vsGetSymFromAddr(mi, addr, disp); if (!si) return NULL; si2se(si, &mi->vsTmpSym); if (disp) *disp = addr - si->Address; return &mi->vsTmpSym; }