2020-09-30 17:12:29 +02:00

756 lines
21 KiB
C

/*++
Revision History:
2-Feb-95 a-robw (Bob Watson)
Made changes for windows95 compatibility:
Replaced KdPrint & DbgPrint functions with CapDbgPrint
"ifdef'd" the calls to the secondary symbol searches with
the _SECOND_CHANCE_LOOKUP macro
Replaced Module Scanning logic with functions supported by
PSAPI.DLL
10-Feb-95 a-robw (Bob Watson)
minor bug fixes
--*/
#include "cap.h"
/********************** G e t F u n c t i o n N a m e **********************
*
* GetFunctionName (ulFuncAddr, ulProfBlkOff, pulSymAddress) -
* This routine is called to find the function name associated
* with the specifed address.
*
* ENTRY ulFuncAddr - address within the function
* ulProfBlkOff - offset of first prof block of module list
*
* EXIT -none-
*
* RETURN pointer to the function name
*
* WARNING:
* -none-
*
* COMMENT:
* -none-
*
*/
/**************** cache test *************/
DWORD is_code_calls = 0;
DWORD is_code_cache_hits = 0;
DWORD is_code_tests = 0;
PTCHAR GetFunctionName (ULONG ulFuncAddr,
ULONG ulProfBlkOff,
ULONG * pulSymAddress)
{
PSYMINFO psyminfo;
int iCount; // 061693 Add
DWORD sigword;
int fAccessViolation = 0;
PIMAGEHLP_SYMBOL pImHelpSym;
IMAGEHLP_MODULE ImHelpModule;
DWORD dwSymbDisp;
PPROFBLK pProfBlk;
PTCHAR ptchSymbName;
TCHAR atchOutName[MAXNAMELENGTH];
TCHAR atchUnDName[MAXNAMELENGTH];
#if defined(MIPS) || defined(ALPHA) || defined(_PPC_)
ULONG ulOffsetFromTopRoutine;
PATCHCODE *pPatchStub;
#endif
#ifdef ALPHA
// BUGBUG
// Does this really need to be UNALIGNED ? These are instructions after all.
//
PULONG UNALIGNED pulAddr;
#elif defined(_PPC_)
PULONG pulAddr;
#endif
if (fLoadLibraryOn)
{
if (ulFuncAddr == (ULONG)CAP_LoadLibraryA)
{
strcpy((PCHAR)atchFuncName, "KERNel32.DLL:LoadLibraryA");
if (pulSymAddress)
{
*pulSymAddress = (ULONG)loadlibAaddr;
}
return(atchFuncName);
}
else if (ulFuncAddr == (ULONG)CAP_LoadLibraryExA)
{
strcpy((PCHAR)atchFuncName, "KERNel32.DLL:LoadLibraryExA");
if (pulSymAddress)
{
*pulSymAddress = (ULONG)loadlibExAaddr;
}
return(atchFuncName);
}
#ifndef _CHICAGO_
else if (ulFuncAddr == (ULONG)CAP_LoadLibraryW)
{
strcpy((PCHAR)atchFuncName, "KERNel32.DLL:LoadLibraryW");
if (pulSymAddress)
{
*pulSymAddress = (ULONG)loadlibWaddr;
}
return(atchFuncName);
}
else if (ulFuncAddr == (ULONG)CAP_LoadLibraryExW)
{
strcpy((PCHAR)atchFuncName, "KERNel32.DLL:LoadLibraryExW");
if (pulSymAddress)
{
*pulSymAddress = (ULONG)loadlibExWaddr;
}
return(atchFuncName);
}
#endif // !_CHICAGO_
}
INFOPrint(("CAP: Looking up symbol for addr [%08lx]\n", ulFuncAddr));
try // EXCEPT - to handle access violation exception.
{ // Access violation might happen while trying to use other processes
// profile blocks..
//
// XXX davidfie -- Why is this here? Can the server side processing cause faults
// other than stub checking? I don't think so but I'll leave this here for
// further investigation.
#ifdef i386
try // If this was a server side address we will probably fault here
{
sigword = *(PDWORD)(ulFuncAddr + 7);
}
//
// + : transfer control to the handler (EXCEPTION_EXECUTE_HANDLER)
// 0 : continue search (EXCEPTION_CONTINUE_SEARCH)
// - : dismiss exception & continue (EXCEPTION_CONTINUE_EXECUTION)
//
except (1)
{
fAccessViolation = 1;
}
// If this is a stub, find out the real address
if (!fAccessViolation && (sigword == STUB_SIGNATURE))
{
// If it is a stub we won't fault because this process must have created it
// and not the server side.
ulFuncAddr = (ULONG) (*(PDWORD)(ulFuncAddr + 1));
}
else
{
// if not a stub adjust address to start of function
ulFuncAddr = ulFuncAddr - 5;
}
#elif MIPS
#ifdef MIPS_VC40_INTERFACE
// Check for stub signature at end of stub patch
if (*((PULONG)ulFuncAddr + 5) == STUB_SIGNATURE)
{
// extract real function address from stub
pPatchStub = (PPATCHCODE)(ulFuncAddr - 5 * INST_SIZE);
ulFuncAddr = (pPatchStub->Lui_t0 << 16);
ulFuncAddr |= (pPatchStub->Ori_t0 & 0x0000ffff);
}
else
{
// Normal function - subtract offset of penter call
ulFuncAddr = ulFuncAddr - 12;
}
#else
//
// Compute the real address of the function since the penter
// stub is not located at the beginning of the code as in x86
//
ulOffsetFromTopRoutine = *((PULONG) (ulFuncAddr - INST_SIZE));
ulOffsetFromTopRoutine &= 0x000ff00;
ulOffsetFromTopRoutine >>= 8;
ulFuncAddr = ulFuncAddr - ulOffsetFromTopRoutine;
// We have to distinguish between a stub and a regular function
// since a stub has a different setup than a regular function.
if (*( (PULONG) ulFuncAddr - 1 +
(sizeof(PATCHCODE) / INST_SIZE) ) == STUB_SIGNATURE)
{
// These are the stubs we made up for Dll Patching
pPatchStub = (PPATCHCODE) ulFuncAddr;
ulFuncAddr = (pPatchStub->Lui_t0 << 16);
ulFuncAddr |= (pPatchStub->Ori_t0 & 0x0000ffff);
}
#endif // MIPS_VC40_INTERFACE
#elif ALPHA // endif MIPS
//
// Compute the real address of the function since the penter
// stub is not located at the beginning of the code as in x86
//
ulFuncAddr = ulFuncAddr - INST_SIZE;
// We have to distinguish between a stub and a regular function
// since a stub has a different setup than a regular function.
pulAddr = (PULONG UNALIGNED) ulFuncAddr;
if (*(pulAddr) == 0x681b4000 &&
(*(pulAddr + 1) == 0xa41e0000) &&
(*(pulAddr + 7) == STUB_SIGNATURE) )
{
// get the address that we will go after the penter function
ulFuncAddr = *(pulAddr + 3) & 0x0000ffff;
if (*(pulAddr + 4) & 0x00008000)
{
// fix the address since we have to add one when
// we created our stub code
ulFuncAddr -= 1;
}
ulFuncAddr = ulFuncAddr << 16;
ulFuncAddr |= *(pulAddr + 4) & 0x0000ffff;
}
#elif defined(_PPC_) // ifdef ALPHA
//
// Compute the real address of the function since the penter
// stub is not located at the beginning of the code as in x86
//
// The RealFuncAddr recorded should be instruction following
// bl ..__penter instruction which is 12 bytes past entry pt.
ulFuncAddr = ulFuncAddr - 12;
// We have to distinguish between a stub and a regular function
// since a stub has a different setup than a regular function.
pulAddr = (PULONG UNALIGNED) ulFuncAddr;
if (*(pulAddr) == 0x7D6903A6 &&
(*(pulAddr + 1) == 0x7C0802A6) &&
(*(pulAddr + 2) == 0x4E800421) &&
(*(pulAddr + 10) == STUB_SIGNATURE) )
{
// get the address that we will go after the penter function
ulFuncAddr = *(pulAddr + 4) & 0x0000ffff;
ulFuncAddr = ulFuncAddr << 16;
ulFuncAddr |= *(pulAddr + 5) & 0x0000ffff;
}
#endif
// Locate module that contains the address
while (ulProfBlkOff != 0)
{
pProfBlk = MKPPROFBLK(ulProfBlkOff);
if ( (ulFuncAddr >= (ULONG)pProfBlk->CodeStart) &&
(ulFuncAddr < ((ULONG)pProfBlk->CodeStart +
(ULONG)pProfBlk->CodeLength)) )
break;
ulProfBlkOff = pProfBlk->ulNxtBlk;
}
// if module found
if (ulProfBlkOff != 0)
{
// Start name with module name
iCount = sprintf (atchFuncName,"%s:",pProfBlk->atchImageName);
// Now locate the symbol itself
psyminfo = SymBSearch (ulFuncAddr,
MKPSYMBLK(pProfBlk->ulSym),
pProfBlk->iSymCnt);
// if symbol found at or below our address
if (psyminfo && ulFuncAddr >= psyminfo->ulAddr)
{
// append symbol name, undecorated if requested
/* if (fUndecorateName) */
/* { */
/* UnDecorateSymbolName(MKPSYMBOL(psyminfo->ulSymOff), &atchFuncName[iCount], */
/* MAXNAMELENGTH - iCount - 10, UNDNAME_NO_MS_KEYWORDS); */
/* } */
/* else */
{
strcpy(&atchFuncName[iCount], MKPSYMBOL(psyminfo->ulSymOff));
}
// if not exact match, append displacement
if (ulFuncAddr > psyminfo->ulAddr)
sprintf(atchFuncName + strlen(atchFuncName),"+0x%x",
ulFuncAddr - psyminfo->ulAddr);
}
else
{
// if no symbol, just append address
sprintf(&atchFuncName[iCount],"0x%08x", ulFuncAddr);
}
}
else
{
// if unknown module, return ????:address
sprintf(atchFuncName,"???:0x%08x",ulFuncAddr);
}
if (pulSymAddress)
*pulSymAddress = ulFuncAddr;
}
//
// + : transfer control to the handler (EXCEPTION_EXECUTE_HANDLER)
// 0 : continue search (EXCEPTION_CONTINUE_SEARCH)
// - : dismiss exception & continue (EXCEPTION_CONTINUE_EXECUTION)
//
except ( AccessXcptFilter (GetExceptionCode(),
GetExceptionInformation(),
PAGE_SIZE) )
{
//
// Should never get here since filter never returns
// EXCEPTION_EXECUTE_HANDLER.
//
CapDbgPrint ("CAP: GetFunctionname() - *LOGIC ERROR* - "
"Inside the EXCEPT: (xcpt=0x%lx)\n", GetExceptionCode());
}
return (atchFuncName);
} /* GetFunctionName () */
/************************** G e t S e c t i o n L i s t F r o m A d d r e s s *****************************
*
* GetSectionListFromAddress (pulAddress)
* This routine finds the section array for the module based on an
* address in the module.
*
* ENTRY pulAddress - an address in a module
*
* EXIT cNumberOfSections - The number of sections in the array.
* ppvCalleBase - The base of the module the address is in.
*
* RETURN a pointer to the begining of the array of sections for the module
* or NULL
*
* WARNING:
* -none-
*
* COMMENT:
* The address isn't checked for validity so a stack or heap address would
* have an unknown effect.
*
*/
PIMAGE_SECTION_HEADER
GetSectionListFromAddress(
IN PULONG pulAddress,
OUT int *cNumberOfSections,
OUT PVOID *ppvCalleeImageBase
)
{
PLIST_ENTRY Next;
PIMAGE_NT_HEADERS pImageNtHeader;
PIMAGE_SECTION_HEADER pSections;
HANDLE hThisProcess;
HMODULE hImageModule;
MODULEINFO miData;
DWORD dwReqdSize;
DWORD dwModuleIndex;
DWORD dwLastModule;
HMODULE *hmTemp;
static HMODULE *hmArray = NULL;
static DWORD dwArraySize;
//
// Get image base from address by chaining down the
// loader table (stolen from DoDllInitializations) and
// and looking for an image which contains the thunked
// address
//
*ppvCalleeImageBase = NULL;
hThisProcess = GetCurrentCapProcess();
hImageModule = GetModuleHandle(NULL);
// If first time, get array for 100 modules
if (hmArray == NULL)
{
dwArraySize = 100 * sizeof(HMODULE);
hmArray = (HMODULE * ) GlobalAlloc (GPTR, dwArraySize);
if (hmArray == NULL)
return NULL;
}
// get module List
while (1)
{
dwReqdSize = 0;
// Get list of loaded modules
EnumProcessModules (
hThisProcess,
hmArray,
dwArraySize,
&dwReqdSize);
// if buffer was big enough, we can continue
if (dwReqdSize <= dwArraySize)
break;
// realloc to the required size
hmTemp = (HMODULE * )GlobalReAlloc(hmArray, dwReqdSize, 0);
if (hmTemp != NULL)
{
hmArray = hmTemp;
dwArraySize = dwReqdSize;
}
else
{
return NULL;
}
}
dwLastModule = dwReqdSize / sizeof(HMODULE);
// get processes exe module handle;
// walk module list to see which module contatins the desired address
for (dwModuleIndex = 0; dwModuleIndex < dwLastModule; dwModuleIndex++) {
GetModuleInformation (
hThisProcess,
hmArray[dwModuleIndex],
&miData,
sizeof(MODULEINFO));
if ((pulAddress > (PULONG)miData.lpBaseOfDll) &&
(pulAddress < (PULONG)((ULONG)miData.lpBaseOfDll +
miData.SizeOfImage))) {
*ppvCalleeImageBase = miData.lpBaseOfDll;
break;
}
} /* end for each module in image */
if (*ppvCalleeImageBase == NULL)
return(NULL);
//
// Get sectionlist from image base
//
pImageNtHeader = ImageNtHeader (*ppvCalleeImageBase);
if (pImageNtHeader == NULL)
return(NULL);
*cNumberOfSections = pImageNtHeader->FileHeader.NumberOfSections;
return(IMAGE_FIRST_SECTION(pImageNtHeader));
}
/************************** I s C o d e A d d r e s s *****************************
*
* IsCodeAddress(pulAddress, pSection, pvImageBase)
* This routine finds the section array for the module based on an
* address in the module.
*
* ENTRY pulAddress - an address in a module
* pSection - a section array in which to look for the address
* cNumberOfSections - the number of sections in the section array
* pvImageBase - the base of the image in which the address is located
*
* EXIT -none-
*
* RETURN TRUE - if the pointer is in a code section or if it's
not in any section which indicates its a forwarder.
* FALSE - otherwize
*
* WARNING:
* If data imports are forwarded this code will break. The way
* to fix would be to call GetSectionListFromAddress() with the
* forwarded address and the recursively call IsCodeAddress().
* There aren't any known forwarded data instances so.....
*
* COMMENT:
* On PPC, pulAddress may be indirect to executable code, via
* a pointer to a function descriptor. This may need a revisit
* if function descriptors are moved out of .reldata.
*
*/
BOOL
IsCodeAddress(
IN PULONG pulAddress,
IN PIMAGE_SECTION_HEADER pSection,
IN int cNumberOfSections,
IN PVOID pvImageBase
)
{
int i;
static last_match = 1;
if (pSection == NULL) return FALSE; // no section == no code address
for ( i=0 ; i < cNumberOfSections ; i++, pSection++)
{
ULONG SectionAddress =(ULONG)pvImageBase + pSection->VirtualAddress;
is_code_tests++;
#ifndef _PPC_
if (((ULONG)pulAddress >= SectionAddress) &&
((ULONG)pulAddress < (SectionAddress + pSection->Misc.VirtualSize)))
#else
if (((ULONG)*pulAddress >= SectionAddress) &&
((ULONG)*pulAddress < (SectionAddress + pSection->Misc.VirtualSize)))
#endif
{
if (i == last_match) is_code_cache_hits++;
is_code_calls++;
last_match = i;
if (pSection->Characteristics & IMAGE_SCN_CNT_CODE)
return(TRUE);
else
return(FALSE);
}
}
OutputCapDebugString("CAP: IsCodeAddress() found forwarded import assuming it"
" is code and not data\n");
return(TRUE); // this must be a forwarder
// so we'll assume it's code
}
/************************** G e t C o d e S e c t i o n T a b l e *****************************
*
* GetCodeSectionTable(pImageDbgInfo, *CNumberOfSections)
* This routine builds an array which can be used to see if a section
* of an object is a code section.
*
* ENTRY pvImageBase - the base of the image in which the address is located
*
* EXIT -none-
*
* RETURN NULL - if it can't build the array
* otherwize - the array
*
* COMMENT:
*
*/
PBOOL
GetCodeSectionTable(
IN PIMAGE_DEBUG_INFORMATION pImageDbgInfo,
OUT int *cNumberOfSections
)
{
int i;
PIMAGE_SECTION_HEADER pSection;
PBOOL CodeSection;
*cNumberOfSections = pImageDbgInfo->NumberOfSections;
pSection = pImageDbgInfo->Sections;
CodeSection = LocalAlloc(LMEM_ZEROINIT, *cNumberOfSections*sizeof(BOOL));
if (CodeSection != NULL)
{
for ( i=0 ; i < *cNumberOfSections ; i++, pSection++)
{
if (pSection->Characteristics & IMAGE_SCN_CNT_CODE)
CodeSection[i] = TRUE;
}
}
return(CodeSection);
}
/******************* S e t S y m b o l S e a r c h P a t h ******************
*
* SetSymbolSearchPath ()
* Return complete search path for symbols files (.dbg)
*
* ENTRY -none-
*
* EXIT -none-
*
* RETURN -none-
*
* WARNING:
* -none-
*
* COMMENT:
* "lpSymbolSearchPath" global LPSTR variable will point to the
* search path.
*/
#define FilePathLen 256
void SetSymbolSearchPath (void)
{
CHAR SymPath[FilePathLen];
CHAR AltSymPath[FilePathLen];
CHAR SysRootPath[FilePathLen];
LPSTR lpSymPathEnv=SymPath;
LPSTR lpAltSymPathEnv=AltSymPath;
LPSTR lpSystemRootEnv=SysRootPath;
ULONG cbSymPath;
DWORD dw;
HANDLE hMemoryHandle;
SymPath[0] = AltSymPath[0] = SysRootPath[0] = '\0';
cbSymPath = 18;
if (GetEnvironmentVariable("_NT_SYMBOL_PATH", SymPath, sizeof(SymPath)))
{
cbSymPath += strlen(lpSymPathEnv) + 1;
}
if (GetEnvironmentVariable("_NT_ALT_SYMBOL_PATH", AltSymPath, sizeof(AltSymPath)))
{
cbSymPath += strlen(lpAltSymPathEnv) + 1;
}
if (GetEnvironmentVariable("SystemRoot", SysRootPath, sizeof(SysRootPath)))
{
cbSymPath += strlen(lpSystemRootEnv) + 1;
}
hMemoryHandle = GlobalAlloc (GHND, cbSymPath+1);
if (!hMemoryHandle)
{
return;
}
lpSymbolSearchPath = GlobalLock (hMemoryHandle);
if (!lpSymbolSearchPath)
{
return;
}
if (*lpAltSymPathEnv)
{
dw = GetFileAttributes(lpAltSymPathEnv);
if ( dw != 0xffffffff && dw & FILE_ATTRIBUTE_DIRECTORY )
{
strcat(lpSymbolSearchPath,lpAltSymPathEnv);
strcat(lpSymbolSearchPath,";");
}
}
if (*lpSymPathEnv)
{
dw = GetFileAttributes(lpSymPathEnv);
if ( dw != 0xffffffff && dw & FILE_ATTRIBUTE_DIRECTORY )
{
strcat(lpSymbolSearchPath,lpSymPathEnv);
strcat(lpSymbolSearchPath,";");
}
}
if (*lpSystemRootEnv)
{
dw = GetFileAttributes(lpSystemRootEnv);
if ( dw != 0xffffffff && dw & FILE_ATTRIBUTE_DIRECTORY )
{
strcat(lpSymbolSearchPath,lpSystemRootEnv);
strcat(lpSymbolSearchPath,";");
}
}
strcat(lpSymbolSearchPath,".;");
} /* SetSymbolSearchPath () */
/************************ S y m B C o m p a r e ******************************
*
* SymBCompare(PDWORD pdwVal1, PSYMINFO val2)
*
* Compare values for Binary search
*
*
* ENTRY: pdwVal1 - value to be comapred against
* val2 - structure address to be comapred against
*
* EXIT: -none-
*
* RETUEN: -1 if val1 < val2
* 1 if val1 > val2
* 0 if val1 == val2
*
* WARNING:
* -none-
*
* COMMENT:
* -none-
*
*/
int SymBCompare (PDWORD pdwVal1, PSYMINFO val2)
{
return (*pdwVal1 < val2->ulAddr ? -1:
*pdwVal1 == val2->ulAddr ?
0 : 1);
} /* SymBCompare () */
/*********************** S y m B S e a r c h *******************************
*
* SymBSearch(DWORD dwAddr, SYMINFO syminfoCur[], INT n)
*
* Binary search function for finding a match in the SYMINFO array
*
*
* ENTRY: dwAddr - Address of calling function
* syminfoCur[] - Pointer to SYMINFO containg value to match
* with dwAddr
* n - Number of elements in SYMINFO array
*
* EXIT -none-
*
* RETUEN: PSYMINFO Pointer to matching or nearest SYMINFO
*
* WARNING:
* -none-
*
* COMMENT:
* -none-
*
*/
PSYMINFO SymBSearch (DWORD dwAddr, SYMINFO syminfoCur[], INT n)
{
int i;
ULONG ulHigh = n;
ULONG ulLow = 0;
ULONG ulMid;
if (n==0)
return NULL;
while (ulLow < ulHigh)
{
ulMid = ulHigh - (ulHigh - ulLow) / 2;
if ((i = SymBCompare(&dwAddr, &syminfoCur[ulMid])) < 0)
{
ulHigh = ulMid - 1;
}
else if (i > 0)
{
ulLow = ulMid;
}
else
{
return (&syminfoCur[ulMid]);
}
}
return &syminfoCur[ulLow];
} /* SymBSearch () */