Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1516 lines
34 KiB

#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <assert.h>
#include <imagehlp.h>
#include <dbhpriv.h>
#include <cvconst.h>
#include <cmnutil.hpp>
#ifndef true
#define true TRUE
#define false FALSE
#endif
#define MAX_STR 256
#define WILD_UNDERSCORE 1
#define SYM_BUFFER_SIZE (sizeof(IMAGEHLP_SYMBOL64) + MAX_SYM_NAME)
#define SI_BUFFER_SIZE (sizeof(SYMBOL_INFO) + MAX_SYM_NAME)
BOOL gDisplay = true;
DWORD gcEnum = 0;
DWORD gcAddr = 0;
#define pprintf (gDisplay)&&printf
typedef struct _GENINFO {
HANDLE hp;
char modname[MAX_PATH + 1];
} GENINFO, *PGENINFO;
typedef struct {
char mask[MAX_STR];
DWORD64 base;
} ENUMSYMDATA, *PENUMSYMDATA;
typedef enum
{
cmdQuit = 0,
cmdHelp,
cmdVerbose,
cmdLoad,
cmdUnload,
cmdEnum,
cmdName,
cmdAddr,
cmdBase,
cmdNext,
cmdPrev,
cmdLine,
cmdSymInfo,
cmdDiaVer,
cmdUndec,
cmdFindFile,
cmdEnumSrcFiles,
cmdAdd,
cmdDelete,
cmdSymbolServer,
cmdEnumForAddr,
cmdLocals,
cmdMax
};
typedef BOOL (*CMDPROC)(char *params);
typedef struct _CMD
{
char token[MAX_STR + 1];
char shorttoken[4];
CMDPROC fn;
} CMD, *PCMD;
BOOL fnQuit(char *);
BOOL fnHelp(char *);
BOOL fnVerbose(char *);
BOOL fnLoad(char *);
BOOL fnUnload(char *);
BOOL fnEnum(char *);
BOOL fnName(char *);
BOOL fnAddr(DWORD64 addr);
BOOL fnBase(char *);
BOOL fnNext(char *);
BOOL fnPrev(char *);
BOOL fnLine(char *);
BOOL fnSymInfo(char *);
BOOL fnDiaVer(char *);
BOOL fnUndec(char *);
BOOL fnFindFile(char *);
BOOL fnEnumSrcFiles(char *);
BOOL fnAdd(char *);
BOOL fnDelete(char *);
BOOL fnSymbolServer(char *);
BOOL fnEnumForAddr(char *);
BOOL fnLocals(char *);
CMD gCmd[cmdMax] =
{
{"quit", "q", fnQuit},
{"help", "h", fnHelp},
{"verbose", "v", fnVerbose},
{"load", "l", fnLoad},
{"unload", "u", fnUnload},
{"enum", "x", fnEnum},
{"name", "n", fnName},
{"addr", "a", fnLoad},
{"base", "b", fnBase},
{"next", "t", fnNext},
{"prev", "v", fnPrev},
{"line", "i", fnLine},
{"sym" , "s", fnSymInfo},
{"dia", "d", fnDiaVer},
{"undec", "n", fnUndec},
{"ff", "f", fnFindFile},
{"src", "r", fnEnumSrcFiles},
{"add", "+", fnAdd},
{"del", "-", fnDelete},
{"ss", "y", fnSymbolServer},
{"enumaddr","m", fnEnumForAddr},
{"locals", "z", fnLocals}
};
char gModName[MAX_STR];
char gImageName[MAX_STR];
char gSymbolSearchPath[MAX_STR];
DWORD64 gBase;
DWORD64 gDefaultBase;
DWORD64 gDefaultBaseForVirtualMods;
DWORD gOptions;
HANDLE gHP;
// symbol server stuff
HINSTANCE ghSrv;
PSYMBOLSERVERPROC gfnSymbolServer;
PSYMBOLSERVERCLOSEPROC gfnSymbolServerClose;
PSYMBOLSERVERSETOPTIONSPROC gfnSymbolServerSetOptions;
PSYMBOLSERVERGETOPTIONSPROC gfnSymbolServerGetOptions;
int
WINAPIV
dprintf(
LPSTR Format,
...
)
{
static char buf[1000] = "DBGHELP: ";
va_list args;
if ((gOptions & SYMOPT_DEBUG) == 0)
return 1;
va_start(args, Format);
_vsnprintf(buf, sizeof(buf)-9, Format, args);
va_end(args);
fputs(buf, stdout);
return 1;
}
__inline int ucase(int c)
{
return (gOptions & SYMOPT_CASE_INSENSITIVE) ? toupper(c) : c;
}
#define MAX_FORMAT_STRINGS 8
char *
dispaddr(
ULONG64 addr
)
/*++
Routine Description:
Format a 64 bit address, showing the high bits or not
according to various flags. This version does not print
leading 0's.
An array of static string buffers is used, returning a different
buffer for each successive call so that it may be used multiple
times in the same dprintf.
Arguments:
addr - Supplies the value to format
Return Value:
A pointer to the string buffer containing the formatted number
--*/
{
static char sz[20];
if ((addr >> 32) != 0)
PrintString(sz, DIMA(sz), "%x`%08x", (ULONG)(addr>>32), (ULONG)addr);
else
PrintString(sz, DIMA(sz), "%x", (ULONG)addr);
return sz;
}
BOOL
validnum(
char *sz
)
{
int c;
for (; *sz; sz++)
{
c = tolower(*sz);
if (c >= '0' && c <= '9')
continue;
if (c >= 'a' && c <= 'f')
continue;
return false;
}
return true;
}
DWORD64
sz2addr(
char *sz
)
{
char *p;
DWORD64 addr = 0;
if (sz && *sz)
{
p = sz;
if (*(p + 1) == 'x' || *(p + 1) == 'X')
p += 2;
if (!validnum(p))
return 0;
if (sscanf(p, "%I64x", &addr) < 1)
return 0;
}
return addr;
}
void dumpsym(
PIMAGEHLP_SYMBOL64 sym
)
{
pprintf(" name : %s\n", sym->Name);
pprintf(" addr : %s\n", dispaddr(sym->Address));
pprintf(" size : %x\n", sym->Size);
pprintf("flags : %x\n", sym->Flags);
}
void dumpsym32(
PIMAGEHLP_SYMBOL sym
)
{
pprintf(" name : %s\n", sym->Name);
pprintf(" addr : %s\n", dispaddr(sym->Address));
pprintf(" size : %x\n", sym->Size);
pprintf("flags : %x\n", sym->Flags);
}
void dumpline(
PIMAGEHLP_LINE64 line
)
{
pprintf("%s %s %d\n", dispaddr(line->Address), line->FileName, line->LineNumber);
}
char* g_SymTagNames[] =
{
"SymTagNull",
"SymTagExe",
"SymTagCompiland",
"SymTagCompilandDetails",
"SymTagCompilandEnv",
"SymTagFunction",
"SymTagBlock",
"SymTagData",
"SymTagAnnotation",
"SymTagLabel",
"SymTagPublicSymbol",
"SymTagUDT",
"SymTagEnum",
"SymTagFunctionType",
"SymTagPointerType",
"SymTagArrayType",
"SymTagBaseType",
"SymTagTypedef",
"SymTagBaseClass",
"SymTagFriend",
"SymTagFunctionArgType",
"SymTagFuncDebugStart",
"SymTagFuncDebugEnd",
"SymTagUsingNamespace",
"SymTagVTableShape",
"SymTagVTable",
"SymTagCustom",
"SymTagThunk",
"SymTagCustomType",
"SymTagManagedType",
"SymTagDimension",
};
char* dispsymtag(
ULONG symtag
)
{
if (symtag >= SymTagMax) {
return "<Invalid>";
} else {
return g_SymTagNames[symtag];
}
}
void dumpsi(
PSYMBOL_INFO si
)
{
pprintf(" name : %s\n", si->Name);
pprintf(" addr : %s\n", dispaddr(si->Address));
pprintf(" size : %x\n", si->Size);
pprintf(" flags : %x\n", si->Flags);
pprintf(" type : %x\n", si->TypeIndex);
pprintf("modbase : %s\n", dispaddr(si->ModBase));
pprintf(" value : %s\n", dispaddr(si->Value));
pprintf(" reg : %x\n", si->Register);
pprintf(" scope : %s (%x)\n", dispsymtag(si->Scope), si->Scope);
pprintf(" tag : %s (%x)\n", dispsymtag(si->Tag), si->Tag);
}
BOOL
MatchPattern(
char *sz,
char *pattern
)
{
char c, p, l;
if (!*pattern)
return true;
for (; ;) {
p = *pattern++;
p = (char)ucase(p);
switch (p) {
case 0: // end of pattern
return *sz ? false : true; // if end of string true
case '*':
while (*sz) { // match zero or more char
if (MatchPattern (sz++, pattern)) {
return true;
}
}
return MatchPattern (sz, pattern);
case '?':
if (*sz++ == 0) { // match any one char
return false; // not end of string
}
break;
case WILD_UNDERSCORE:
while (*sz == '_') {
sz++;
}
break;
case '[':
if ( (c = *sz++) == 0) { // match char set
return false; // syntax
}
c = (CHAR)ucase(c);
l = 0;
while (p = *pattern++) {
if (p == ']') { // if end of char set, then
return false; // no match found
}
if (p == '-') { // check a range of chars?
p = *pattern; // get high limit of range
if (p == 0 || p == ']') {
return false; // syntax
}
if (c >= l && c <= p) {
break; // if in range, move on
}
}
l = p;
if (c == p) { // if char matches this element
break; // move on
}
}
while (p && p != ']') { // got a match in char set
p = *pattern++; // skip to end of set
}
break;
default:
c = *sz++;
if (ucase(c) != p) { // check for exact char
return false; // not a match
}
break;
}
}
}
BOOL
cbEnumSymbols(
PSYMBOL_INFO si,
ULONG size,
PVOID context
)
{
PENUMSYMDATA esd = (PENUMSYMDATA)context;
if (gDisplay)
{
pprintf(" %8s : ", dispaddr(si->Address));
if (si->Flags & SYMF_FORWARDER)
pprintf("%c ", 'F');
else if (si->Flags & SYMF_EXPORT)
pprintf("%c ", 'E');
else
pprintf(" ");
pprintf("%s\n", si->Name);
}
gcEnum++;
gcAddr++;
fnAddr(si->Address + 2);
return true;
}
BOOL
cbEnumSym(
PTSTR name,
DWORD64 address,
ULONG size,
PVOID context
)
{
PENUMSYMDATA esd = (PENUMSYMDATA)context;
if (MatchPattern(name, esd->mask))
pprintf("%s : %s\n", dispaddr(address), name);
return true;
}
BOOL
cbSrcFiles(
PSOURCEFILE pSourceFile,
PVOID UserContext
)
{
DWORD dw;
BOOL rc;
LONG disp;
IMAGEHLP_LINE64 line;
GENINFO *gi = (GENINFO *)UserContext;
if (!pSourceFile)
return false;
if (!strcmp(pSourceFile->FileName, "d:\\pat\\test\\test.c")
|| !strcmp(pSourceFile->FileName, "d:\\pat\\lines\\lines.c"))
{
pprintf("%s\n", pSourceFile->FileName);
}
else
pprintf("%s\n", pSourceFile->FileName);
if (!gi)
return true;
line.SizeOfStruct = sizeof(line);
rc = SymGetLineFromName64(gi->hp, gi->modname, pSourceFile->FileName, 1, &disp, &line);
#if 0
for (dw = line.LineNumber + 1; rc; dw = line.LineNumber + 1) {
dumpline(&line);
rc = SymGetLineFromName64(gi->hp, gi->modname, pSourceFile->FileName, dw, &disp, &line);
}
#else
while (rc)
{
dumpline(&line);
rc = SymGetLineNext64(gi->hp, &line);
}
do {
rc = SymGetLinePrev64(gi->hp, &line);
if (rc)
dumpline(&line);
} while (rc);
#endif
return true;
}
BOOL
cbSymbol(
HANDLE hProcess,
ULONG ActionCode,
ULONG64 CallbackData,
ULONG64 UserContext
)
{
PIMAGEHLP_DEFERRED_SYMBOL_LOAD64 idsl;
PIMAGEHLP_CBA_READ_MEMORY prm;
IMAGEHLP_MODULE64 mi;
PUCHAR p;
ULONG i;
idsl = (PIMAGEHLP_DEFERRED_SYMBOL_LOAD64) CallbackData;
switch ( ActionCode ) {
case CBA_DEBUG_INFO:
dprintf("%s", (LPSTR)CallbackData);
break;
#if 0
case CBA_DEFERRED_SYMBOL_LOAD_CANCEL:
if (fControlC)
{
fControlC = 0;
return true;
}
break;
#endif
case CBA_DEFERRED_SYMBOL_LOAD_START:
dprintf("loading symbols for %s\n", gModName);
break;
case CBA_DEFERRED_SYMBOL_LOAD_FAILURE:
if (idsl->FileName && *idsl->FileName)
dprintf( "*** Error: could not load symbols for %s\n", idsl->FileName );
else
dprintf( "*** Error: could not load symbols [MODNAME UNKNOWN]\n");
break;
case CBA_DEFERRED_SYMBOL_LOAD_COMPLETE:
break;
case CBA_SYMBOLS_UNLOADED:
dprintf("unloaded symbols for %s\n", gModName);
break;
#if 0
case CBA_READ_MEMORY:
prm = (PIMAGEHLP_CBA_READ_MEMORY)CallbackData;
return g_Target->ReadVirtual(prm->addr,
prm->buf,
prm->bytes,
prm->bytesread) == S_OK;
#endif
default:
return false;
}
return false;
}
BOOL fnQuit(char *param)
{
pprintf("goodbye\n");
return false;
}
BOOL fnHelp(char *param)
{
pprintf(" dbh commands :\n");
pprintf("h help : prints this message\n");
pprintf("q quit : quits this program\n");
pprintf("v verbose <on/off> : controls debug spew\n");
pprintf("l load <modname> : loads the requested module\n");
pprintf("u unload : unloads the current module\n");
pprintf("x enum <mask> : enumerates all matching symbols\n");
pprintf("n name <symname> : finds a symbol by it's name\n");
pprintf("a addr <addr> : finds a symbol by it's hex address\n");
pprintf("m enumaddr <addr> : lists all symbols with a certain hex address\n");
pprintf("b base <address> : sets the new default base address\n");
pprintf("t next <add/nam> : finds the symbol after the passed sym\n");
pprintf("v prev <add/nam> : finds the symbol before the passed sym\n");
pprintf("i line <file:#> : finds the matching line number\n");
pprintf("s sym : displays type and location of symbols\n");
pprintf("d dia : displays the DIA version\n");
pprintf("f ff <path> <file> : finds file in path\n");
pprintf("r src <mask> : lists source files\n");
pprintf("+ add <name addr> : adds symbols with passed name and address\n");
pprintf("- del <name/addr> : deletes symbols with passed name or address\n");
pprintf("y ss : executes a symbol server command\n");
pprintf("m enumaddr <addr> : enum all symbols for address\n");
pprintf("z locals <name> : enum all scoped symbols for a named function\n");
return true;
}
BOOL fnVerbose(char *param)
{
int opts = gOptions;
if (!param || !*param)
pprintf("");
else if (!_strcmpi(param, "on"))
opts |= SYMOPT_DEBUG;
else if (!_strcmpi(param, "off"))
opts = gOptions & ~SYMOPT_DEBUG;
else
pprintf("verbose <on//off>\n");
gOptions = SymSetOptions(opts);
pprintf("verbose mode %s.\n", gOptions & SYMOPT_DEBUG ? "on" : "off");
return true;
}
BOOL fnLoad(char *param)
{
char ext[MAX_STR];
char mod[MAX_STR];
char image[MAX_STR];
DWORD flags = 0;
DWORD64 addr = 0;
CopyStrArray(image, (param && *param) ? param : "VIRTUAL");
_splitpath(image, NULL, NULL, mod, ext);
if (!*ext) {
flags = SLMFLAG_VIRTUAL;
addr = gDefaultBaseForVirtualMods;
} else if (!_strcmpi(ext, ".pdb")) {
addr = gDefaultBaseForVirtualMods;
} else {
addr = gDefaultBase;
}
fnUnload(NULL);
CopyStrArray(gModName, mod);
addr = SymLoadModuleEx(gHP,
NULL, // hFile,
param, // ImageName,
mod, // ModuleName,
addr, // BaseOfDll,
0x1000000, // SizeOfDll
NULL, // Data
flags); // Flags
if (!addr)
{
*gModName = 0;
pprintf("error 0x%x loading %s\n", GetLastError(), param);
return false;
}
if (gBase && !SymUnloadModule64(gHP, gBase))
pprintf("error unloading %s at %s\n", gModName, dispaddr(gBase));
CopyStrArray(gImageName, image);
gBase = addr;
return true;
}
BOOL fnUnload(char *param)
{
if (!gBase)
return true;
if (!SymUnloadModule64(gHP, gBase))
pprintf("error unloading %s at %s\n", gModName, dispaddr(gBase));
gBase = 0;
*gModName = 0;
return true;
}
BOOL fnEnum(char *param)
{
BOOL rc;
ENUMSYMDATA esd;
esd.base = gBase;
CopyStrArray(esd.mask, param ? param : "");
rc = SymEnumSymbols(gHP, gBase, param, cbEnumSymbols, &esd);
if (!rc)
pprintf("error 0x%0 calling SymEnumSymbols()\n", GetLastError());
return true;
}
BOOL fnEnumSrcFiles(char *param)
{
BOOL rc;
GENINFO gi;
gi.hp = gHP;
CopyStrArray(gi.modname, gModName);
rc = SymEnumSourceFiles(gHP, gBase, param, cbSrcFiles, &gi);
if (!rc)
pprintf("error 0x%0 calling SymEnumSourceFiles()\n", GetLastError());
return true;
}
BOOL fnName(char *param)
{
#if 0
BOOL rc;
PIMAGEHLP_SYMBOL64 sym;
char name[MAX_STR];
if (!param || !*param)
{
pprintf("name <symbolname> - finds a symbol by it's name\n");
return true;
}
PrintString(name, DIMA(name), "%s!%s", gModName, param);
sym = malloc(SYM_BUFFER_SIZE);
if (!sym)
return false;
ZeroMemory(sym, SYM_BUFFER_SIZE);
sym->MaxNameLength = MAX_SYM_NAME;
if (SymGetSymFromName64(gHP, name, sym))
if (gDisplay)
dumpsym(sym);
free(sym);
return true;
#else
PSYMBOL_INFO si;
char name[MAX_STR];
if (!param || !*param)
{
pprintf("name <symbolname> - finds a symbol by it's name\n");
return true;
}
PrintString(name, DIMA(name), "%s!%s", gModName, param);
si = (PSYMBOL_INFO)malloc(SI_BUFFER_SIZE);
if (!si)
return false;
ZeroMemory(si, SI_BUFFER_SIZE);
si->MaxNameLen = MAX_SYM_NAME;
if (SymFromName(gHP, name, si))
dumpsi(si);
free(si);
return true;
#endif
}
BOOL fnAddr(DWORD64 addr)
{
BOOL rc;
PIMAGEHLP_SYMBOL64 sym;
DWORD64 disp;
PSYMBOL_INFO si;
IMAGEHLP_LINE64 line;
DWORD ldisp;
if (!addr)
{
pprintf("addr <address> : finds a symbol by it's hex address\n");
return true;
}
#if 0
sym = (PIMAGEHLP_SYMBOL64)malloc(SYM_BUFFER_SIZE);
if (!sym)
return false;
ZeroMemory(sym, SYM_BUFFER_SIZE);
sym->MaxNameLength = MAX_SYM_NAME;
rc = SymGetSymFromAddr64(gHP, addr, &disp, sym);
if (rc)
{
if (gDisplay)
{
pprintf("%s", sym->Name);
if (disp)
pprintf("+%I64x", disp);
pprintf("\n");
dumpsym(sym);
}
}
free(sym);
line.SizeOfStruct = sizeof(line);
rc = SymGetLineFromAddr64(gHP, addr, &ldisp, &line);
if (rc && gDisplay)
pprintf("%s %d\n", line.FileName, line.LineNumber);
#else
si = (PSYMBOL_INFO)malloc(SI_BUFFER_SIZE);
if (!si)
return false;
ZeroMemory(si, SI_BUFFER_SIZE);
si->MaxNameLen = MAX_SYM_NAME;
rc = SymFromAddr(gHP, addr, &disp, si);
if (rc)
{
pprintf("%s", si->Name);
if (disp)
pprintf("+%I64x", disp);
pprintf("\n");
dumpsi(si);
}
free(si);
line.SizeOfStruct = sizeof(line);
rc = SymGetLineFromAddr64(gHP, addr, &ldisp, &line);
if (rc && gDisplay)
pprintf("%s %d\n", line.FileName, line.LineNumber);
#endif
return true;
}
BOOL fnEnumForAddr(char *param)
{
BOOL rc;
PIMAGEHLP_SYMBOL64 sym;
DWORD64 addr;
DWORD64 disp;
ENUMSYMDATA esd;
addr = sz2addr(param);
if (!addr)
{
pprintf("enumaddr <addr> : lists all symbols with a certain hex address\n");
return true;
}
esd.base = gBase;
CopyStrArray(esd.mask, "");
rc = SymEnumSymbolsForAddr(gHP, addr, cbEnumSymbols, &esd);
if (!rc)
pprintf("error 0x%0 calling SymEnumSymbolsForAddr()\n", GetLastError());
return true;
}
BOOL fnLocals(char *param)
{
BOOL rc;
PSYMBOL_INFO si;
char name[MAX_STR];
IMAGEHLP_STACK_FRAME frame;
ENUMSYMDATA esd;
SYMBOL_INFO_PACKAGE sp;
if (!param || !*param)
{
pprintf("name <symbolname> - finds a symbol by it's name\n");
return true;
}
PrintString(name, DIMA(name), "%s!%s", gModName, param);
si = (PSYMBOL_INFO)malloc(SI_BUFFER_SIZE);
if (!si)
return false;
ZeroMemory(si, SI_BUFFER_SIZE);
si->MaxNameLen = MAX_SYM_NAME;
if (!SymFromName(gHP, name, si))
goto exit;
pprintf("dumping locals for %s...\n", si->Name);
ZeroMemory(&frame, sizeof(frame));
frame.InstructionOffset = si->Address;
SymSetContext(gHP, &frame, NULL);
esd.base = gBase;
CopyStrArray(esd.mask, "*");
if (!SymEnumSymbols(gHP, 0, esd.mask, cbEnumSymbols, &esd))
pprintf("error 0x%0 calling SymEnumSymbols()\n", GetLastError());
exit:
free(si);
return true;
}
PIMAGEHLP_SYMBOL64 SymbolFromName(char *param)
{
BOOL rc;
PIMAGEHLP_SYMBOL64 sym;
char name[MAX_STR];
assert(name & *name);
sym = (PIMAGEHLP_SYMBOL64)malloc(SYM_BUFFER_SIZE);
if (!sym)
return false;
ZeroMemory(sym, SYM_BUFFER_SIZE);
sym->MaxNameLength = MAX_SYM_NAME;
PrintString(name, DIMA(name), "%s!%s", gModName, param);
rc = SymGetSymFromName64(gHP, name, sym);
if (!rc) {
free(sym);
return NULL;
}
return sym;
}
BOOL fnNextPrev(int direction, char *param)
{
#if 1
BOOL rc;
PIMAGEHLP_SYMBOL64 sym;
DWORD64 addr;
char name[MAX_STR];
addr = sz2addr(param);
if (!addr)
{
sym = SymbolFromName(param);
if (!sym)
return true;
addr = sym->Address;
if (!addr) {
free(sym);
return true;
}
}
else
{
sym = (PIMAGEHLP_SYMBOL64)malloc(SYM_BUFFER_SIZE);
if (!sym)
return false;
}
if (direction > 0)
rc = SymGetSymNext64(gHP, sym);
else
rc = SymGetSymPrev64(gHP, sym);
if (rc && gDisplay)
dumpsym(sym);
free(sym);
return true;
#else
BOOL rc;
PIMAGEHLP_SYMBOL sym;
DWORD64 addr;
char name[MAX_STR];
DWORD disp;
sym = malloc(SYM_BUFFER_SIZE);
if (!sym)
return false;
sym->MaxNameLength = MAX_STR;
addr = sz2addr(param);
if (!addr)
rc = SymGetSymFromName(gHP, param, sym);
else
rc = SymGetSymFromAddr(gHP, (DWORD)addr, &disp, sym);
if (rc) {
if (direction > 0)
rc = SymGetSymNext(gHP, sym);
else
rc = SymGetSymPrev(gHP, sym);
if (rc & gDisplay)
dumpsym32(sym);
}
free(sym);
return true;
#endif
}
BOOL fnNext(char *param)
{
return fnNextPrev(1, param);
}
BOOL fnPrev(char *param)
{
return fnNextPrev(-1, param);
}
BOOL fnBase(char *param)
{
BOOL rc;
PIMAGEHLP_SYMBOL64 sym;
DWORD64 addr;
DWORD64 disp;
addr = sz2addr(param);
if (!addr)
{
pprintf("base <address> : sets the base address for module loads\n");
return true;
}
gDefaultBase = addr;
gDefaultBaseForVirtualMods = addr;
if (gBase)
fnLoad(gImageName);
return true;
}
BOOL fnLine(char *param)
{
char *file;
DWORD linenum;
BOOL rc;
IMAGEHLP_LINE64 line;
LONG disp;
if (!param || !*param)
return true;
file = param;
while (*param != ':') {
if (!*param)
return true;
param++;
}
*param++ = 0;
linenum = atoi(param);
if (!linenum)
return true;
memset(&line, 0, sizeof(line));
line.SizeOfStruct = sizeof(IMAGEHLP_LINE64);
rc = SymGetLineFromName64(gHP,
gModName,
file,
linenum,
&disp,
&line);
if (!rc) {
pprintf("line: error 0x%x looking for %s#%d\n",
GetLastError(),
file,
linenum);
return true;
}
pprintf("file : %s\n", line.FileName);
pprintf("line : %d\n", linenum);
pprintf("addr : %s\n", dispaddr(line.Address));
pprintf("disp : %x\n", disp);
return true;
}
BOOL fnSymInfo(char *param)
{
DBH_MODSYMINFO msi;
if (!gBase)
return true;
msi.function = dbhModSymInfo;
msi.sizeofstruct = sizeof(msi);
msi.addr = gBase;
if (!dbghelp(gHP, (PVOID)&msi))
pprintf("error grabbing symbol info\n");
pprintf("%s: symtype=%x, src=%s\n", gModName, msi.type, msi.file);
return true;
}
BOOL fnDiaVer(char *param)
{
DBH_DIAVERSION dv;
dv.function = dbhDiaVersion;
dv.sizeofstruct = sizeof(dv);
if (!dbghelp(0, (PVOID)&dv))
pprintf("error grabbing dia version info\n");
pprintf("DIA version %d\n", dv.ver);
return true;
}
BOOL fnUndec(char *param)
{
DWORD rc;
char uname[MAX_SYM_NAME + 1];
if (!param || !*param)
{
pprintf("undec <symbolname> - undecorates a C++ mangled symbol name\n");
return true;
}
rc = UnDecorateSymbolName(param, uname, MAX_SYM_NAME, UNDNAME_COMPLETE);
if (!rc) {
pprintf("error 0x%u undecorating %s\n", GetLastError(), param);
} else {
pprintf("%s = %s\n", param, uname);
}
return true;
}
BOOL fnFindFile(char *param)
{
DWORD rc;
char root[MAX_PATH + 1];
char file[MAX_PATH + 1];
char found[MAX_PATH + 1];
if (!param)
{
pprintf("ff <root path> <file name> - finds file in path\n");
return true;
}
rc = sscanf(param, "%s %s", root, file);
if ((rc < 2) || !*root || !*file)
{
pprintf("ff <root path> <file name> - finds file in path\n");
return true;
}
*found = 0;
rc = SearchTreeForFile(root, file, found);
if (!rc) {
pprintf("error 0x%u looking for %s\n", GetLastError(), file);
} else {
pprintf("found %s\n", found);
}
return true;
}
BOOL fnAdd(char *param)
{
BOOL rc;
DWORD64 addr;
DWORD size;
char *p;
char name[MAX_STR];
char *n;
if (!param || !*param) {
pprintf("add <name address> : must specify a symbol name and address.\n");
return true;
}
p = param;
while (isspace(*p)) p++;
*name = 0;
for (n = name; *p; p++, n++) {
if (isspace(*p)) {
*n = 0;
break;
}
*n = *p;
}
addr = 0;
size = 0;
while (isspace(*p)) p++;
if (*(p + 1) == 'x' || *(p + 1) == 'X')
p += 2;
rc = sscanf(p, "%I64x %x", &addr, &size);
if ((rc < 2) || !addr || !*name)
{
pprintf("add <name address> : must specify a symbol name and address.\n");
return true;
}
rc = SymAddSymbol(gHP, 0, name, addr, size, 0);
if (!rc)
pprintf("Error 0x%x trying to add symbol\n", GetLastError());
return true;
}
BOOL fnDelete(char *param)
{
BOOL rc;
DWORD64 addr;
DWORD err;
char *name = NULL;
if (!param || !*param) {
pprintf("del <name/address> : must specify a symbol name or address to delete.\n");
return true;
}
addr = sz2addr(param);
if (!addr)
name = param;
rc = SymDeleteSymbol(gHP, 0, name, addr, 0);
if (!rc) {
err = GetLastError();
if (err == ERROR_NOT_FOUND)
pprintf("Couldn't find %s to delete.\n", param);
else
pprintf("Error 0x%x trying to delete symbol\n", err);
}
return true;
}
BOOL fnSymbolServer(char *param)
{
DWORD opt = 0;
DWORD data = 0;
// initialize server, if needed
if (ghSrv == (HINSTANCE)INVALID_HANDLE_VALUE)
return false;
if (!ghSrv) {
ghSrv = (HINSTANCE)INVALID_HANDLE_VALUE;
ghSrv = LoadLibrary("symsrv.dll");
if (ghSrv) {
gfnSymbolServer = (PSYMBOLSERVERPROC)GetProcAddress(ghSrv, "SymbolServer");
if (!gfnSymbolServer) {
FreeLibrary(ghSrv);
ghSrv = (HINSTANCE)INVALID_HANDLE_VALUE;
}
gfnSymbolServerClose = (PSYMBOLSERVERCLOSEPROC)GetProcAddress(ghSrv, "SymbolServerClose");
gfnSymbolServerSetOptions = (PSYMBOLSERVERSETOPTIONSPROC)GetProcAddress(ghSrv, "SymbolServerSetOptions");
gfnSymbolServerGetOptions = (PSYMBOLSERVERGETOPTIONSPROC)GetProcAddress(ghSrv, "SymbolServerGetOptions");
} else {
ghSrv = (HINSTANCE)INVALID_HANDLE_VALUE;
}
}
// bail, if we have no valid server
if (ghSrv == INVALID_HANDLE_VALUE) {
pprintf("SymSrv load failure.\n");
return false;
}
if (param) {
if (sscanf(param, "%x %x", &opt, &data) > 0)
{
if (opt)
gfnSymbolServerSetOptions(opt, data);
}
}
opt = (DWORD)gfnSymbolServerGetOptions();
pprintf("SYMSRV options: 0x%x\n", opt);
return true;
}
char *GetParameters(char *cmd)
{
char *p = cmd;
char *param = NULL;
while (*p++)
{
if (isspace(*p))
{
*p++ = 0;
return *p ? p : NULL;
}
}
return NULL;
}
void prompt()
{
if (!*gModName)
pprintf("dbh: ");
else
pprintf("%s [%I64x]: ", gModName, gBase);
}
int InputLoop()
{
char cmd[MAX_STR + 1];
char *params;
int i;
BOOL rc;
pprintf("\n");
do
{
prompt();
if (!fgets(cmd, sizeof(cmd), stdin))
return 0;
params = GetParameters(cmd);
for (i = 0; i < cmdMax; i++)
{
if (!_strcmpi(cmd, gCmd[i].token) ||
!_strcmpi(cmd, gCmd[i].shorttoken))
break;
}
if (i == cmdMax)
{
pprintf("[%s] is an unrecognized command.\n", cmd);
rc = true;
continue;
}
else
rc = gCmd[i].fn(params);
} while (rc);
return 0;
}
BOOL init()
{
int i;
BOOL rc;
*gModName = 0;
gBase = 0;;
gDefaultBaseForVirtualMods = 0x1000000;
pprintf("dbh: initializing...\n");
i = GetEnvironmentVariable("_NT_SYMBOL_PATH", gSymbolSearchPath, MAX_STR);
if (i < 1)
*gSymbolSearchPath = 0;
pprintf("Symbol Path = [%s]\n", gSymbolSearchPath);
gHP = GetCurrentProcess();
rc = SymInitialize(gHP, gSymbolSearchPath, false);
if (!rc)
{
pprintf("error 0x%x from SymInitialize()\n", GetLastError());
return rc;
}
rc = SymInitialize(gHP, gSymbolSearchPath, false);
if (!rc)
{
pprintf("error 0x%x from SymInitialize()\n", GetLastError());
return rc;
}
gOptions = SymSetOptions(SYMOPT_CASE_INSENSITIVE | SYMOPT_UNDNAME | SYMOPT_LOAD_LINES | SYMOPT_ALLOW_ABSOLUTE_SYMBOLS | SYMOPT_NO_PUBLICS | SYMOPT_DEBUG);
pprintf("SymOpts = 0x%x\n", gOptions);
rc = SymRegisterCallback64(gHP, cbSymbol, 0);
if (!rc)
{
pprintf("error 0x%x from SymRegisterCallback64()\n", GetLastError());
return rc;
}
return rc;
}
void cleanup()
{
int i;
fnUnload(NULL);
for (i = 0; i < 50; i++)
SymCleanup(gHP);
}
BOOL cmdline(int argc, char *argv[])
{
int i;
char *p;
for (i = 1; i < argc; i++)
{
p = argv[i];
switch (*p)
{
case '/':
case '-':
p++;
switch (tolower(*p))
{
case 's':
gDisplay = false;
break;
default:
pprintf("%s is an unknown switch\n", argv[i]);
break;
}
break;
default:
if (!fnLoad(argv[i]))
return false;
break;
}
}
return true;
}
#include <crtdbg.h>
__cdecl
main(
int argc,
char *argv[],
char *envp[]
)
{
DWORD rc = 0;
_CrtSetDbgFlag( ( _CRTDBG_CHECK_ALWAYS_DF | _CRTDBG_LEAK_CHECK_DF ) | _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG ) );
if (!init())
return 1;
if (!cmdline(argc, argv))
return 1;
fnEnum("*");
#if 1
fnEnumSrcFiles("*");
#endif
cleanup();
dprintf("%d symbols enumerated.\n", gcEnum);
dprintf("%d symbols searched by address.\n", gcAddr);
_CrtDumpMemoryLeaks();
return rc;
}