|
|
/*
Copyright 1999 Microsoft Corporation
Neptune data collection server
Walter Smith (wsmith)
Matches Symbols with The Corresponding Binary
*/
#include <windows.h>
#include <dbghelp.h>
#include <symres.h>
#include <stdio.h>
#include <stdlib.h>
#include <shlwapi.h>
#include <sys\stat.h>
#include <string.h>
#undef UNICODE
#include <strsafe.h>
#ifndef DIMA
#define DIMAT(Array, EltType) (sizeof(Array) / sizeof(EltType))
#define DIMA(Array) DIMAT(Array, (Array)[0])
#endif
void UndecorateSymbol( LPTSTR szSymbol // [in] [out] function name undecorated in place
) { char szTemp[MAX_PATH]; PIMAGEHLP_SYMBOL pihsym; DWORD dwSize;
dwSize = sizeof(IMAGEHLP_SYMBOL)+MAX_PATH; pihsym = (IMAGEHLP_SYMBOL *) malloc(dwSize); pihsym->SizeOfStruct = dwSize; pihsym->Address = 0; pihsym->Flags = 0; pihsym->MaxNameLength = MAX_PATH; wcstombs(pihsym->Name,szSymbol, lstrlen(szSymbol)); SymUnDName(pihsym,szTemp,MAX_PATH); mbstowcs(szSymbol,szTemp, strlen(szTemp)); }
// select file from list of open files, or open and add to list
// maintain files in usage order, least recently used at end of list
OPENFILE* // pointer to open file info
SymbolResolver::GetFile( LPWSTR szwModule // [in] name of file
) { OPENFILE* pFile = NULL; MAPDEF map; DWORD dwCread; WCHAR wszBuffer[MAX_PATH];
StringCchCopyW(wszBuffer, DIMA(wszBuffer), szwModule); PathRemoveExtension(wszBuffer); PathAddExtension(wszBuffer, L".sym");
pFile = new OPENFILE; // open SYM file
pFile->hfFile = CreateFileW(wszBuffer, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (pFile->hfFile == INVALID_HANDLE_VALUE) return NULL; // copy filename and version into pFile node
StringCchCopyW(pFile->szwName, DIMA(pFile->szwName), szwModule);
// read map definition
ReadFile(pFile->hfFile, &map, sizeof(MAPDEF)-1, &dwCread, NULL);
if (dwCread != sizeof(MAPDEF)-1) { if (pFile->hfFile) CloseHandle(pFile->hfFile); if (pFile) delete pFile; throw E_FAIL; }
pFile->ulFirstSeg = map.md_spseg*16; pFile->nSeg = map.md_cseg; pFile->psCurSymDefPtrs = NULL;
return pFile; }
// parse sym file to resolve address
// read segment defintion for dwSection
ULONG // return offset of segment definition, 0 if failed
SymbolResolver::GetSegDef(OPENFILE* pFile, // [in] pointer to open file info
DWORD dwSection, // [in] section number
SEGDEF* pSeg) // [out] pointer to segment definition
{ ULONG ulCurSeg = pFile->ulFirstSeg; int iSectionIndex = 0; DWORD dwCread;
// step through segments
while (iSectionIndex < pFile->nSeg) { // go to segment beginning
if (SetFilePointer(pFile->hfFile, ulCurSeg, NULL, FILE_BEGIN) == 0xFFFFFFFF) { ulCurSeg = 0; break; }
// read seg defn
if (!ReadFile(pFile->hfFile, pSeg, sizeof(SEGDEF)-1, &dwCread, NULL)) { ulCurSeg = 0; break; }
iSectionIndex++; if (iSectionIndex == (int)dwSection) // gotcha
{ break; }
// go to next segment definition
ulCurSeg = pSeg->gd_spsegnext*16; }
// found our section and it's non-empty?
if (iSectionIndex != (int)dwSection || !pSeg->gd_csym) // no
{ ulCurSeg = 0; }
return ulCurSeg; }
// parse sym file to resolve address
bool SymbolResolver::GetNameFromAddr( LPWSTR szwModule, // [in] name of symbol file
DWORD dwSection, // [in] section part of address to resolve
DWORD dwOffsetToRva, // [in] Section base
UINT_PTR uRva, // [in] offset part of address to resolve
LPWSTR wszFuncName // [out] resolved function name,
) { SEGDEF seg; DWORD dwSymAddr; TCHAR sztFuncName[MAX_NAME+1]; int i; int nNameLen; DWORD dwCread; int nToRead; unsigned char cName; ULONG ulCurSeg; ULONG ulSymNameOffset = 0; HANDLE hfFile; OPENFILE* pFile = NULL; DWORD dwArrayOffset; DWORD dwSymOffset; bool fResult = false;
// get file from open list, or open file
pFile = GetFile(szwModule);
if (!pFile) return false;
if ((ulCurSeg = GetSegDef(pFile, dwSection, &seg)) == 0) { goto Cleanup; }
BYTE* pSymDefPtrs;
// big symbols?
if (seg.gd_type & MSF_BIGSYMDEF) { dwArrayOffset = seg.gd_psymoff * 16; pSymDefPtrs = (BYTE*)(new BYTE[seg.gd_csym*3]); } else { dwArrayOffset = seg.gd_psymoff; pSymDefPtrs = (BYTE*)(new BYTE[seg.gd_csym*2]); } hfFile = pFile->hfFile;
SetFilePointer(hfFile, ulCurSeg + dwArrayOffset, NULL, FILE_BEGIN);
// read symbol definition pointers array
ReadFile(hfFile, pSymDefPtrs, seg.gd_csym * ((seg.gd_type & MSF_BIGSYMDEF)?3:2), &dwCread, NULL);
pFile->psCurSymDefPtrs = pSymDefPtrs;
// save this section
pFile->dwCurSection = dwSection;
// read symbols
for (i = 0; i < seg.gd_csym; i++) { // go to offset of sym defintion
if (seg.gd_type & MSF_BIGSYMDEF) { dwSymOffset = pFile->psCurSymDefPtrs[i*3+0] + pFile->psCurSymDefPtrs[i*3+1]*256 + pFile->psCurSymDefPtrs[i*3+2]*65536; } else { dwSymOffset = pFile->psCurSymDefPtrs[i*2+0] + pFile->psCurSymDefPtrs[i*2+1]*256; }
SetFilePointer(hfFile, ulCurSeg + dwSymOffset, NULL, FILE_BEGIN);
// read symbol address DWORD
ReadFile(hfFile,&dwSymAddr,sizeof(DWORD),&dwCread,NULL);
// symbol address is 1 word or two?
nToRead = sizeof(SHORT) + ((seg.gd_type & MSF_32BITSYMS) * sizeof(SHORT));
// calculate offset of symbol name
ulSymNameOffset = ulCurSeg + dwSymOffset + nToRead;
// use just lower word of address if 16-bit symbol
if (!(seg.gd_type & MSF_32BITSYMS)) { dwSymAddr = dwSymAddr & 0x0000FFFF; } dwSymAddr += dwOffsetToRva;
if (dwSymAddr > uRva ) break; if (dwSymAddr == uRva ) { // do we have our function?
// if current address is greater than offset, then since we are
// traversing in the increasing order of addresses, the previous
// symbol must be our quarry
SetFilePointer(hfFile, ulSymNameOffset, NULL, FILE_BEGIN);
// read length of name
ReadFile(hfFile,&cName,sizeof(TCHAR),&dwCread,NULL);
nNameLen = (int) cName;
// read symbol name
ReadFile(hfFile,sztFuncName,nNameLen,&dwCread,NULL);
sztFuncName[nNameLen/2 - (nNameLen+1)%2] = TCHAR('\0');
UndecorateSymbol(sztFuncName);
StrCpyNW(wszFuncName, sztFuncName, MAX_NAME); fResult = true; } }
Cleanup:
if (pFile->hfFile) CloseHandle(pFile->hfFile);
if (pFile->psCurSymDefPtrs) delete pFile->psCurSymDefPtrs;
if (pFile) delete pFile;
return fResult; }
|