windows-nt/Source/XPSP1/NT/sdktools/profiler/view.c
2020-09-26 16:20:57 +08:00

819 lines
18 KiB
C

#include <windows.h>
#include <stdio.h>
#include "view.h"
#include "except.h"
#include "disasm.h"
#include "dump.h"
#include "profiler.h"
#include "memory.h"
#include "filter.h"
static PVIEWCHAIN *ppViewHead = 0;
static CRITICAL_SECTION viewCritSec;
static CRITICAL_SECTION mapCritSec;
static PTAGGEDADDRESS pTagHead = 0;
static PBRANCHADDRESS pBranchHead = 0;
BOOL
InitializeViewData(VOID)
{
InitializeCriticalSection(&viewCritSec);
InitializeCriticalSection(&mapCritSec);
//
// Allocate hashing data
//
ppViewHead = (PVIEWCHAIN *)AllocMem(sizeof(PVIEWCHAIN) * (MAX_MAP_SIZE >> MAP_STRIDE_BITS));
if (0 == ppViewHead) {
return FALSE;
}
return TRUE;
}
PVIEWCHAIN
AddViewToMonitor(DWORD dwAddress,
BPType bpType)
{
PVIEWCHAIN pView;
DWORD dwHash;
//
// If address is higher than the map size, fail it
//
if (dwAddress >= MAX_MAP_SIZE) {
return 0;
}
//
// This occurs when a call tries to map over an existing trace breakpoint
//
if (*(BYTE *)dwAddress == X86_BREAKPOINT) {
return 0;
}
//
// Check if we're filtering this address
//
if (TRUE == IsAddressFiltered(dwAddress)) {
return 0;
}
//
// Allocate a chain entry
//
pView = AllocMem(sizeof(VIEWCHAIN));
if (0 == pView) {
return 0;
}
pView->bMapped = FALSE;
pView->bTraced = FALSE;
pView->dwAddress = dwAddress;
pView->dwMapExtreme = dwAddress;
pView->jByteReplaced = *(BYTE *)dwAddress;
pView->bpType = bpType;
//
// Set a breakpoint at the top of the code
//
WRITEBYTE(dwAddress, X86_BREAKPOINT);
EnterCriticalSection(&viewCritSec);
//
// Add view point to monitor list
//
dwHash = dwAddress >> MAP_STRIDE_BITS;
if (0 == ppViewHead[dwHash]) {
ppViewHead[dwHash] = pView;
}
else {
//
// Chain to head
//
pView->pNext = ppViewHead[dwHash];
ppViewHead[dwHash] = pView;
}
LeaveCriticalSection(&viewCritSec);
return pView;
}
PVIEWCHAIN
RestoreAddressFromView(DWORD dwAddress,
BOOL bResetData)
{
BOOL bResult = FALSE;
PVIEWCHAIN pTemp;
EnterCriticalSection(&viewCritSec);
pTemp = ppViewHead[dwAddress >> MAP_STRIDE_BITS];
while (pTemp) {
//
// Is this our entry
//
if (dwAddress == pTemp->dwAddress) {
//
// Set a breakpoint at the top of the code
//
if (TRUE == bResetData) {
WRITEBYTE(dwAddress, pTemp->jByteReplaced);
}
else {
WRITEBYTE(dwAddress, X86_BREAKPOINT);
}
//
// Return with modified data
//
break;
}
pTemp = pTemp->pNext;
}
LeaveCriticalSection(&viewCritSec);
return pTemp;
}
PVIEWCHAIN
FindView(DWORD dwAddress) {
PVIEWCHAIN pTemp;
if (dwAddress >= MAX_MAP_SIZE) {
return 0;
}
EnterCriticalSection(&viewCritSec);
pTemp = ppViewHead[dwAddress >> MAP_STRIDE_BITS];
while (pTemp) {
//
// See if address is mapped
//
if (dwAddress == pTemp->dwAddress) {
LeaveCriticalSection(&viewCritSec);
return pTemp;
}
pTemp = pTemp->pNext;
}
LeaveCriticalSection(&viewCritSec);
return 0;
}
BOOL
MapCode(PVIEWCHAIN pvMap) {
BOOL bResult;
DWORD dwCurrent;
DWORD *pdwAddress;
DWORD *pdwTemp;
PCHAR pCode;
PVIEWCHAIN pvTemp;
DWORD dwLength;
DWORD dwJumpEIP;
LONG lOffset;
DWORD dwInsLength;
DWORD dwTemp;
BYTE tempCode[32];
BYTE jOperand;
DWORD dwProfileEnd = 0;
CHAR szBuffer[MAX_PATH];
//
// Map termination through all conditionals
//
dwCurrent = pvMap->dwAddress;
//
// Take the mapping lock
//
LockMapper();
//
// Forward scan through code to find termination
//
while(1) {
strncpy(tempCode, (PCHAR)dwCurrent, 32);
//
// Make sure the instruction is unmodified
//
if (tempCode[0] == (BYTE)X86_BREAKPOINT) {
//
// Rebuild instruction without breakpoints
//
pvTemp = FindView(dwCurrent);
if (pvTemp) {
//
// Replace the bytes if we have a match
//
tempCode[0] = pvTemp->jByteReplaced;
}
}
//
// Calculate instruction length
//
dwInsLength = GetInstructionLengthFromAddress((PVOID)tempCode);
//
// Follow a forward trace through jumps to the ret
//
if ((tempCode[0] >= (BYTE)0x70) && (tempCode[0] <= (BYTE)0x7f)) {
//
// Update the end of the region marker
//
if (dwCurrent > dwProfileEnd) {
dwProfileEnd = dwCurrent;
}
//
// Relative branch
//
dwJumpEIP = (dwCurrent + 2 + (CHAR)(tempCode[1]));
//
// Mark this branch as executed
//
bResult = AddTaggedAddress(dwCurrent);
if (FALSE == bResult) {
return FALSE;
}
if (dwJumpEIP > dwCurrent) {
//
// Push the opposite branch
//
bResult = PushBranch(dwCurrent + dwInsLength);
if (FALSE == bResult) {
return FALSE;
}
dwCurrent = dwJumpEIP;
}
else {
//
// Push the opposite branch
//
bResult = PushBranch(dwJumpEIP);
if (FALSE == bResult) {
return FALSE;
}
dwCurrent += dwInsLength;
}
continue;
}
if (tempCode[0] == (BYTE)0x0f) {
if ((tempCode[1] >= (BYTE)0x80) && (tempCode[1] <= (BYTE)0x8f)) {
//
// Update the end of the region marker
//
if (dwCurrent > dwProfileEnd) {
dwProfileEnd = dwCurrent;
}
//
// Relative branch
//
dwJumpEIP = (dwCurrent + 6 + *(LONG *)(&(tempCode[2])));
//
// Mark this branch as executed
//
bResult = AddTaggedAddress(dwCurrent);
if (FALSE == bResult) {
return FALSE;
}
if (dwJumpEIP > dwCurrent) {
//
// Push the opposite branch
//
bResult = PushBranch(dwCurrent + dwInsLength);
if (FALSE == bResult) {
return FALSE;
}
dwCurrent = dwJumpEIP;
}
else {
//
// Push the opposite branch
//
bResult = PushBranch(dwJumpEIP);
if (FALSE == bResult) {
return FALSE;
}
dwCurrent += dwInsLength;
}
continue;
}
}
if (tempCode[0] == (BYTE)0xe3) {
//
// Update the end of the region marker
//
if (dwCurrent > dwProfileEnd) {
dwProfileEnd = dwCurrent;
}
//
// Relative branch
//
dwJumpEIP = (dwCurrent + 2 + (CHAR)(tempCode[1]));
//
// Mark this branch as executed
//
bResult = AddTaggedAddress(dwCurrent);
if (FALSE == bResult) {
return FALSE;
}
if (dwJumpEIP > dwCurrent) {
//
// Push the opposite branch
//
bResult = PushBranch(dwCurrent + dwInsLength);
if (FALSE == bResult) {
return FALSE;
}
dwCurrent = dwJumpEIP;
}
else {
//
// Push the opposite branch
//
bResult = PushBranch(dwJumpEIP);
if (FALSE == bResult) {
return FALSE;
}
dwCurrent += dwInsLength;
}
continue;
}
if (tempCode[0] == (BYTE)0xeb) {
//
// Update the end of the region marker
//
if (dwCurrent > dwProfileEnd) {
dwProfileEnd = dwCurrent;
}
//
// Jump relative
//
dwJumpEIP = (dwCurrent + 2 + (CHAR)(tempCode[1]));
//
// Mark this branch as executed
//
bResult = AddTaggedAddress(dwCurrent);
if (FALSE == bResult) {
return FALSE;
}
//
// Jmp must always be followed
//
dwCurrent = dwJumpEIP;
continue;
}
if (tempCode[0] == (BYTE)0xe9) {
//
// Update the end of the region marker
//
if (dwCurrent > dwProfileEnd) {
dwProfileEnd = dwCurrent;
}
//
// Jump relative
//
dwJumpEIP = (dwCurrent + 5 + *(LONG *)(&(tempCode[1])));
//
// Mark this branch as executed
//
bResult = AddTaggedAddress(dwCurrent);
if (FALSE == bResult) {
return FALSE;
}
//
// Jump must always be followed
//
dwCurrent = dwJumpEIP;
continue;
}
//
// Probe for calls and jumps
//
if (tempCode[0] == (BYTE)0xff) {
//
// Tests for whether this is a call or not
//
jOperand = (tempCode[1] >> 3) & 7;
if ((jOperand == 2) ||
(jOperand == 3) ||
(jOperand == 4) ||
(jOperand == 5)) {
//
// Update the end of the region marker
//
if (dwCurrent > dwProfileEnd) {
dwProfileEnd = dwCurrent;
}
//
// Add our mapping breakpoint with the appropriate type
//
if ((jOperand == 2) ||
(jOperand == 3)) {
pvTemp = AddViewToMonitor(dwCurrent,
Call);
if (pvTemp) {
pvTemp->bMapped = TRUE;
}
}
else {
//
// These kinds of jumps are always a break (there's no way to forward trace them)
//
pvTemp = AddViewToMonitor(dwCurrent,
Jump);
if (pvTemp) {
pvTemp->bMapped = TRUE;
}
else {
//
// Special case for mapping breakpoints which really are just jumps
//
pvTemp = FindView(dwCurrent);
if (pvTemp) {
pvTemp->bMapped = TRUE;
pvTemp->bpType = Jump;
}
}
//
// Mark this branch as executed
//
bResult = AddTaggedAddress(dwCurrent);
if (FALSE == bResult) {
return FALSE;
}
//
// Dump the tree
//
dwTemp = PopBranch();
if (dwTemp) {
dwCurrent = dwTemp;
continue;
}
break;
}
}
}
if (tempCode[0] == (BYTE)0xe8) {
//
// Update the end of the region marker
//
if (dwCurrent > dwProfileEnd) {
dwProfileEnd = dwCurrent;
}
//
// Add this top call to the view
//
pvTemp = AddViewToMonitor(dwCurrent,
Call);
if (pvTemp) {
pvTemp->bMapped = TRUE;
}
}
if (tempCode[0] == (BYTE)0x9a) {
//
// Update the end of the region marker
//
if (dwCurrent > dwProfileEnd) {
dwProfileEnd = dwCurrent;
}
//
// Add this top call to the view
//
pvTemp = AddViewToMonitor(dwCurrent,
Call);
if (pvTemp) {
pvTemp->bMapped = TRUE;
}
}
if (tempCode[0] == (BYTE)0xea) {
//
// Update the end of the region marker
//
if (dwCurrent > dwProfileEnd) {
dwProfileEnd = dwCurrent;
}
//
// Absolute far jumps are a terminating condition - flush all branches
//
pvTemp = AddViewToMonitor(dwCurrent,
Jump);
if (pvTemp) {
pvTemp->bMapped = TRUE;
}
//
// Mark this branch as executed
//
bResult = AddTaggedAddress(dwCurrent);
if (FALSE == bResult) {
return FALSE;
}
//
// Dump the tree
//
dwTemp = PopBranch();
if (dwTemp) {
dwCurrent = dwTemp;
continue;
}
break;
}
if (*(WORD *)(&(tempCode[0])) == 0xffff) {
//
// Update the end of the region marker
//
if (dwCurrent > dwProfileEnd) {
dwProfileEnd = dwCurrent;
}
//
// This is also a trace path terminator - see if we need to trace more conditions
//
dwTemp = PopBranch();
if (dwTemp) {
//
// We have a branch to follow
//
dwCurrent = dwTemp;
continue;
}
//
// Update the end of the address range
//
break;
}
if (tempCode[0] == (BYTE)0xc3) {
//
// This is also a trace path terminator - see if we need to trace more conditions
//
if (dwCurrent > dwProfileEnd) {
dwProfileEnd = dwCurrent;
}
dwTemp = PopBranch();
if (dwTemp) {
//
// We have a branch to follow
//
dwCurrent = dwTemp;
continue;
}
break;
}
if (tempCode[0] == (BYTE)0xc2) {
//
// This is also a trace path terminator - see if we need to trace more conditions
//
if (dwCurrent > dwProfileEnd) {
dwProfileEnd = dwCurrent;
}
dwTemp = PopBranch();
if (dwTemp) {
//
// We have a branch to follow
//
dwCurrent = dwTemp;
continue;
}
break;
}
dwCurrent += dwInsLength;
}
if (dwProfileEnd) {
pvMap->dwMapExtreme = dwProfileEnd;
}
else {
pvMap->dwMapExtreme = dwCurrent;
}
bResult = WriteMapInfo(pvMap->dwAddress,
pvMap->dwMapExtreme);
if (!bResult) {
return FALSE;
}
//
// Restore the code we've whacked around
//
bResult = RestoreTaggedAddresses();
if (FALSE == bResult) {
return FALSE;
}
//
// Assert if this _ever_ happens
//
if (pBranchHead != 0) {
Sleep(20000);
_asm int 3
}
//
// We're mapped
//
pvMap->bMapped = TRUE;
//
// Release the mapping lock
//
UnlockMapper();
return TRUE;
}
//
// Trace helpers
//
BOOL
AddTaggedAddress(DWORD dwAddress)
{
PTAGGEDADDRESS pTagTemp;
DWORD dwTempAddress;
//
// Make sure we haven't addressed this tag
//
if (*(WORD *)dwAddress == 0xFFFF) {
//
// No need since it's already tagged
//
return TRUE;
}
//
// Store off the bytes we are tagging
//
pTagTemp = AllocMem(sizeof(TAGGEDADDRESS));
if (0 == pTagTemp) {
return FALSE;
}
pTagTemp->dwAddress = dwAddress;
pTagTemp->wBytesReplaced = *(WORD *)dwAddress;
//
// Chain the entry
//
if (0 == pTagHead) {
pTagHead = pTagTemp;
}
else {
pTagTemp->pNext = pTagHead;
pTagHead = pTagTemp;
}
//
// Mark this branch as executed
//
WRITEWORD(dwAddress, 0xFFFF);
return TRUE;
}
BOOL
RestoreTaggedAddresses(VOID)
{
PTAGGEDADDRESS pTagTemp;
PTAGGEDADDRESS pTagTemp2;
//
// Walk the tag list and replace the marked branches with their original bytes
//
pTagTemp = pTagHead;
while(pTagTemp) {
//
// Dirty up the code now so the branches can auto terminate
//
WRITEWORD(pTagTemp->dwAddress, pTagTemp->wBytesReplaced);
pTagTemp2 = pTagTemp;
pTagTemp = pTagTemp->pNext;
//
// Dump the old allocated memory
//
FreeMem(pTagTemp2);
}
pTagHead = 0;
return TRUE;
}
BOOL
PushBranch(DWORD dwAddress)
{
PBRANCHADDRESS pBranchTemp;
pBranchTemp = AllocMem(sizeof(BRANCHADDRESS));
if (0 == pBranchTemp) {
return FALSE;
}
pBranchTemp->dwAddress = dwAddress;
if (0 == pBranchHead) {
pBranchHead = pBranchTemp;
}
else {
pBranchTemp->pNext = pBranchHead;
pBranchHead = pBranchTemp;
}
return TRUE;
}
DWORD
PopBranch(VOID)
{
PBRANCHADDRESS pBranchTemp;
DWORD dwAddress = 0;
pBranchTemp = pBranchHead;
if (0 == pBranchTemp) {
return 0;
}
dwAddress = pBranchTemp->dwAddress;
pBranchHead = pBranchHead->pNext;
FreeMem(pBranchTemp);
return dwAddress;
}
VOID
LockMapper(VOID)
{
EnterCriticalSection(&mapCritSec);
}
VOID
UnlockMapper(VOID)
{
LeaveCriticalSection(&mapCritSec);
}