pykd/pykd/win/dbgeng.cpp
SND\kernelnet_cp a10f7ed26b [0.2.x] fixed : !pycmd falled to loop
git-svn-id: https://pykd.svn.codeplex.com/svn@83134 9b283d60-5439-405e-af05-b73fd8c4d996
2017-11-08 17:42:50 +04:00

1528 lines
44 KiB
C++
Raw Blame History

#include "stdafx.h"
#include <boost\algorithm\string\case_conv.hpp>
#include "win/dbgeng.h"
#include "win/dbgio.h"
#include "win/windbg.h"
#include "dbgexcept.h"
#include "eventhandler.h"
#include "symengine.h"
namespace pykd {
///////////////////////////////////////////////////////////////////////////////////
DebugEngine g_dbgEng;
///////////////////////////////////////////////////////////////////////////////////
ULONG startProcess( const std::wstring &processName )
{
PyThread_StateRestore pyThreadRestore( g_dbgEng->pystate );
HRESULT hres;
ULONG opt;
hres = g_dbgEng->control->GetEngineOptions( &opt );
if ( FAILED( hres ) )
throw DbgException( "IDebugControl::GetEngineOptions failed" );
opt |= DEBUG_ENGOPT_INITIAL_BREAK;
hres = g_dbgEng->control->SetEngineOptions( opt );
if ( FAILED( hres ) )
throw DbgException( "IDebugControl::SetEngineOptions failed" );
std::vector< std::wstring::value_type > cmdLine( processName.size() + 1 );
wcscpy_s( &cmdLine[0], cmdLine.size(), processName.c_str() );
hres = g_dbgEng->client->CreateProcessWide( 0, &cmdLine[0], DEBUG_PROCESS | DETACHED_PROCESS );
if ( FAILED( hres ) )
throw DbgException( "IDebugClient4::CreateProcessWide failed" );
hres = g_dbgEng->control->WaitForEvent(DEBUG_WAIT_DEFAULT, INFINITE);
if ( FAILED( hres ) )
throw DbgException( "IDebugControl::WaitForEvent failed" );
ULONG processId = -1;
hres = g_dbgEng->system->GetCurrentProcessId( &processId );
if ( FAILED( hres ) )
throw DbgException( "IDebugSystemObjects::GetCurrentProcessId failed" );
return processId;
}
///////////////////////////////////////////////////////////////////////////////////
ULONG attachProcess( ULONG pid )
{
PyThread_StateRestore pyThreadRestore( g_dbgEng->pystate );
HRESULT hres;
ULONG opt;
hres = g_dbgEng->control->GetEngineOptions( &opt );
if ( FAILED( hres ) )
throw DbgException( "IDebugControl::GetEngineOptions failed" );
opt |= DEBUG_ENGOPT_INITIAL_BREAK;
hres = g_dbgEng->control->SetEngineOptions( opt );
if ( FAILED( hres ) )
throw DbgException( "IDebugControl::SetEngineOptions failed" );
hres = g_dbgEng->client->AttachProcess( 0, pid, 0 );
if ( FAILED( hres ) )
throw DbgException( "IDebugClient::AttachProcess failed" );
hres = g_dbgEng->control->WaitForEvent(DEBUG_WAIT_DEFAULT, INFINITE);
if ( FAILED( hres ) )
throw DbgException( "IDebugControl::WaitForEvent failed" );
ULONG processId = -1;
hres = g_dbgEng->system->GetCurrentProcessId( &processId );
if ( FAILED( hres ) )
throw DbgException( "IDebugSystemObjects::GetCurrentProcessId failed" );
return processId;
}
///////////////////////////////////////////////////////////////////////////////////
void detachProcess( ULONG processId )
{
PyThread_StateRestore pyThreadRestore( g_dbgEng->pystate );
HRESULT hres;
if ( processId != -1 )
{
hres = g_dbgEng->system->SetCurrentProcessId(processId);
if ( FAILED(hres) )
throw DbgException( "IDebugSystemObjects::SetCurrentProcessId failed" );
}
hres = g_dbgEng->client->DetachCurrentProcess();
if ( FAILED( hres ) )
throw DbgException( "IDebugClient::DetachCurrentProcess failed" );
}
///////////////////////////////////////////////////////////////////////////////////
void terminateProcess( ULONG processId )
{
PyThread_StateRestore pyThreadRestore( g_dbgEng->pystate );
HRESULT hres;
if ( processId != -1 )
{
hres = g_dbgEng->system->SetCurrentProcessId(processId);
if ( FAILED(hres) )
throw DbgException( "IDebugSystemObjects::SetCurrentProcessId failed" );
}
hres = g_dbgEng->client->TerminateCurrentProcess();
if ( FAILED( hres ) )
throw DbgException( "IDebugClient::TerminateCurrentProcess", hres );
}
///////////////////////////////////////////////////////////////////////////////////
void loadDump( const std::wstring &fileName )
{
PyThread_StateRestore pyThreadRestore( g_dbgEng->pystate );
HRESULT hres;
hres = g_dbgEng->client->OpenDumpFileWide( fileName.c_str(), NULL );
if ( FAILED( hres ) )
throw DbgException( "IDebugClient4::OpenDumpFileWide failed" );
hres = g_dbgEng->control->WaitForEvent(DEBUG_WAIT_DEFAULT, INFINITE);
if ( FAILED( hres ) )
throw DbgException( "IDebugControl::WaitForEvent failed" );
}
///////////////////////////////////////////////////////////////////////////////////
void writeDump( const std::wstring &fileName, bool smallDump )
{
PyThread_StateRestore pyThreadRestore( g_dbgEng->pystate );
HRESULT hres;
ULONG debugClass, debugQualifier;
hres = g_dbgEng->control->GetDebuggeeType( &debugClass, &debugQualifier );
if ( FAILED( hres ) )
throw DbgException( "IDebugControl::GetDebuggeeType failed" );
hres = g_dbgEng->client->WriteDumpFileWide(
fileName.c_str(),
NULL,
smallDump ? DEBUG_DUMP_SMALL : ( debugClass == DEBUG_CLASS_KERNEL ? DEBUG_DUMP_FULL : DEBUG_DUMP_DEFAULT ),
DEBUG_FORMAT_DEFAULT,
NULL );
if ( FAILED(hres) )
throw DbgException( "IDebugClient4::WriteDumpFileWide failed" );
}
///////////////////////////////////////////////////////////////////////////////////
bool isDumpAnalyzing()
{
PyThread_StateRestore pyThreadRestore( g_dbgEng->pystate );
HRESULT hres;
ULONG debugClass, debugQualifier;
hres = g_dbgEng->control->GetDebuggeeType( &debugClass, &debugQualifier );
if ( FAILED( hres ) )
throw DbgException( "IDebugControl::GetDebuggeeType failed" );
return debugQualifier >= DEBUG_DUMP_SMALL;
}
///////////////////////////////////////////////////////////////////////////////////
bool isKernelDebugging()
{
PyThread_StateRestore pyThreadRestore( g_dbgEng->pystate );
HRESULT hres;
ULONG debugClass, debugQualifier;
hres = g_dbgEng->control->GetDebuggeeType( &debugClass, &debugQualifier );
if ( FAILED( hres ) )
throw DbgException( "IDebugControl::GetDebuggeeType failed" );
return debugClass == DEBUG_CLASS_KERNEL;
}
///////////////////////////////////////////////////////////////////////////////////
void debugGo()
{
PyThread_StateRestore pyThreadRestore( g_dbgEng->pystate );
HRESULT hres;
hres = g_dbgEng->control->SetExecutionStatus( DEBUG_STATUS_GO );
if ( FAILED( hres ) )
throw DbgException( "IDebugControl::SetExecutionStatus failed" );
ULONG currentStatus;
do {
hres = g_dbgEng->control->WaitForEvent(DEBUG_WAIT_DEFAULT, INFINITE);
if ( FAILED( hres ) )
throw DbgException( "IDebugControl::WaitForEvent failed" );
hres = g_dbgEng->control->GetExecutionStatus( &currentStatus );
if ( FAILED( hres ) )
throw DbgException( "IDebugControl::GetExecutionStatus failed" );
} while( currentStatus != DEBUG_STATUS_BREAK && currentStatus != DEBUG_STATUS_NO_DEBUGGEE );
}
///////////////////////////////////////////////////////////////////////////////
void debugStep()
{
PyThread_StateRestore pyThreadRestore( g_dbgEng->pystate );
HRESULT hres;
hres = g_dbgEng->control->SetExecutionStatus( DEBUG_STATUS_STEP_OVER );
if ( FAILED( hres ) )
throw DbgException( "IDebugControl::SetExecutionStatus failed" );
ULONG currentStatus;
do {
hres = g_dbgEng->control->WaitForEvent(DEBUG_WAIT_DEFAULT, INFINITE);
if ( FAILED( hres ) )
throw DbgException( "IDebugControl::WaitForEvent failed" );
hres = g_dbgEng->control->GetExecutionStatus( &currentStatus );
if ( FAILED( hres ) )
throw DbgException( "IDebugControl::GetExecutionStatus failed" );
} while( currentStatus != DEBUG_STATUS_BREAK && currentStatus != DEBUG_STATUS_NO_DEBUGGEE );
}
///////////////////////////////////////////////////////////////////////////////
void debugStepIn()
{
PyThread_StateRestore pyThreadRestore( g_dbgEng->pystate );
HRESULT hres;
hres = g_dbgEng->control->SetExecutionStatus( DEBUG_STATUS_STEP_INTO );
if ( FAILED( hres ) )
throw DbgException( "IDebugControl::SetExecutionStatus failed" );
ULONG currentStatus;
do {
hres = g_dbgEng->control->WaitForEvent(DEBUG_WAIT_DEFAULT, INFINITE);
if ( FAILED( hres ) )
throw DbgException( "IDebugControl::WaitForEvent failed" );
hres = g_dbgEng->control->GetExecutionStatus( &currentStatus );
if ( FAILED( hres ) )
throw DbgException( "IDebugControl::GetExecutionStatus failed" );
} while( currentStatus != DEBUG_STATUS_BREAK && currentStatus != DEBUG_STATUS_NO_DEBUGGEE );
}
///////////////////////////////////////////////////////////////////////////////
void debugBreak()
{
PyThreadState *pystate = PyEval_SaveThread();
HRESULT hres;
hres = g_dbgEng->control->SetInterrupt( DEBUG_INTERRUPT_ACTIVE );
PyEval_RestoreThread( pystate );
if ( FAILED( hres ) )
throw DbgException( "IDebugControl::SetInterrupt" );
}
///////////////////////////////////////////////////////////////////////////////
ULONG64 evaluate( const std::wstring &expression )
{
PyThread_StateRestore pyThreadRestore( g_dbgEng->pystate );
HRESULT hres;
ULONG64 value = 0;
DEBUG_VALUE debugValue = {};
ULONG remainderIndex = 0;
hres = g_dbgEng->control->IsPointer64Bit();
if ( FAILED( hres ) )
throw DbgException( "IDebugControl::IsPointer64Bit failed" );
if ( hres == S_OK )
{
hres = g_dbgEng->control->EvaluateWide(
expression.c_str(),
DEBUG_VALUE_INT64,
&debugValue,
&remainderIndex );
if ( FAILED( hres ) )
throw DbgException( "IDebugControl::Evaluate failed" );
if ( remainderIndex == expression.length() )
value = debugValue.I64;
}
else
{
hres = g_dbgEng->control->EvaluateWide(
expression.c_str(),
DEBUG_VALUE_INT32,
&debugValue,
&remainderIndex );
if ( FAILED( hres ) )
throw DbgException( "IDebugControl::Evaluate failed" );
if ( remainderIndex == expression.length() )
value = debugValue.I32;
}
return value;
}
///////////////////////////////////////////////////////////////////////////////
std::string debugCommand( const std::wstring &command )
{
PyThread_StateRestore pyThreadRestore( g_dbgEng->pystate );
HRESULT hres;
OutputReader outReader( g_dbgEng->client );
hres = g_dbgEng->control->ExecuteWide( DEBUG_OUTCTL_THIS_CLIENT, command.c_str(), 0 );
if ( FAILED( hres ) )
throw DbgException( "IDebugControl::Execute failed" );
return std::string( outReader.Line() );
}
///////////////////////////////////////////////////////////////////////////////
ULONG ptrSize()
{
PyThread_StateRestore pyThreadRestore( g_dbgEng->pystate );
HRESULT hres;
hres = g_dbgEng->control->IsPointer64Bit();
if ( FAILED( hres ) )
throw DbgException( "IDebugControl::IsPointer64Bit failed" );
return S_OK == hres ? 8 : 4;
}
///////////////////////////////////////////////////////////////////////////////////
bool is64bitSystem()
{
PyThread_StateRestore pyThreadRestore( g_dbgEng->pystate );
HRESULT hres;
ULONG procType;
hres = g_dbgEng->control->GetActualProcessorType( &procType );
if ( FAILED( hres ) )
throw DbgException( "IDebugControl::GetActualProcessorType failed" );
return procType == IMAGE_FILE_MACHINE_AMD64;
}
///////////////////////////////////////////////////////////////////////////////
ULONG getPageSize()
{
PyThread_StateRestore pyThreadRestore( g_dbgEng->pystate );
HRESULT hres;
ULONG pageSize;
hres = g_dbgEng->control->GetPageSize( &pageSize );
if ( FAILED( hres ) )
throw DbgException( "IDebugControl::GetPageSize failed" );
return pageSize;
}
///////////////////////////////////////////////////////////////////////////////
ULONG getSystemUptime()
{
PyThread_StateRestore pyThreadRestore( g_dbgEng->pystate );
HRESULT hres;
ULONG time;
hres = g_dbgEng->control->GetCurrentSystemUpTime( &time );
if ( FAILED( hres ) )
throw DbgException( "IDebugControl2::GetCurrentSystemUpTime", hres );
return time;
}
///////////////////////////////////////////////////////////////////////////////
ULONG getCurrentTime()
{
PyThread_StateRestore pyThreadRestore( g_dbgEng->pystate );
HRESULT hres;
ULONG time;
hres = g_dbgEng->control->GetCurrentTimeDate( &time );
if ( FAILED( hres ) )
throw DbgException( "IDebugControl2::GetCurrentTimeDate", hres );
return time;
}
///////////////////////////////////////////////////////////////////////////////
ULONG64 loadMSR( ULONG msr )
{
PyThread_StateRestore pyThreadRestore( g_dbgEng->pystate );
HRESULT hres;
ULONG64 value;
hres = g_dbgEng->dataspace->ReadMsr( msr, &value );
if ( FAILED( hres ) )
throw DbgException( "IDebugDataSpaces::ReadMsr", hres );
return value;
}
///////////////////////////////////////////////////////////////////////////////
void setMSR( ULONG msr, ULONG64 value)
{
PyThread_StateRestore pyThreadRestore( g_dbgEng->pystate );
HRESULT hres;
hres = g_dbgEng->dataspace->WriteMsr(msr, value);
if ( FAILED( hres ) )
throw DbgException( "IDebugDataSpaces::WriteMsr", hres );
}
///////////////////////////////////////////////////////////////////////////////
ULONG getRegIndexByName( const std::string &regName )
{
PyThread_StateRestore pyThreadRestore( g_dbgEng->pystate );
HRESULT hres;
ULONG index;
hres = g_dbgEng->registers->GetIndexByName( boost::to_lower_copy(regName).c_str(), &index );
if ( FAILED( hres ) )
throw DbgException( "IDebugRegister::GetIndexByName", hres );
return index;
}
///////////////////////////////////////////////////////////////////////////////
std::string getRegNameByIndex( ULONG index )
{
PyThread_StateRestore pyThreadRestore( g_dbgEng->pystate );
HRESULT hres;
ULONG nameSize = 0;
hres =
g_dbgEng->registers->GetDescription(
index,
NULL,
0,
&nameSize,
NULL );
if ( nameSize == 0 )
if ( FAILED( hres ) )
throw DbgException( "IDebugRegister::GetDescription", hres );
std::vector<char> nameBuffer(nameSize);
DEBUG_REGISTER_DESCRIPTION desc = {};
hres =
g_dbgEng->registers->GetDescription(
index,
&nameBuffer[0],
nameSize,
NULL,
&desc );
if ( FAILED( hres ) )
throw DbgException( "IDebugRegister::GetDescription", hres );
return std::string( &nameBuffer[0] );
}
///////////////////////////////////////////////////////////////////////////////
BaseTypeVariant getRegVariantValue( ULONG index )
{
PyThread_StateRestore pyThreadRestore( g_dbgEng->pystate );
HRESULT hres;
DEBUG_VALUE debugValue;
hres = g_dbgEng->registers->GetValue( index, &debugValue );
if ( FAILED( hres ) )
throw DbgException( "IDebugRegister::GetValue", hres );
switch( debugValue.Type )
{
case DEBUG_VALUE_INT8:
return BaseTypeVariant( (LONG)debugValue.I8 );
break;
case DEBUG_VALUE_INT16:
return BaseTypeVariant( (LONG)debugValue.I16 );
break;
case DEBUG_VALUE_INT32:
return BaseTypeVariant( debugValue.I32 );
break;
case DEBUG_VALUE_INT64:
return BaseTypeVariant( debugValue.I64 );
break;
}
throw DbgException( "Failed to convert register value" );
}
///////////////////////////////////////////////////////////////////////////////
ULONG64 getRegInstructionPointer()
{
PyThread_StateRestore pyThreadRestore( g_dbgEng->pystate );
HRESULT hres;
ULONG64 ip = 0;
hres = g_dbgEng->registers->GetInstructionOffset( &ip );
if ( FAILED( hres ) )
throw DbgException( "IDebugRegisters::GetInstructionOffset failed" );
return ip;
}
///////////////////////////////////////////////////////////////////////////////
static void buildStacksFrames(
std::vector<STACK_FRAME_DESC> &frames,
ULONG64 frameOffset = 0,
ULONG64 stackOffset = 0,
ULONG64 instructionOffset = 0)
{
ULONG filledFrames = 1024;
std::vector<DEBUG_STACK_FRAME> dbgFrames(filledFrames);
HRESULT hres =
g_dbgEng->control->GetStackTrace(
frameOffset,
stackOffset,
instructionOffset,
&dbgFrames[0],
filledFrames,
&filledFrames);
if (S_OK != hres)
throw DbgException( "IDebugControl::GetStackTrace", hres );
frames.resize(filledFrames);
for ( ULONG i = 0; i < filledFrames; ++i )
{
frames[i].number = dbgFrames[i].FrameNumber;
frames[i].instructionOffset = dbgFrames[i].InstructionOffset;
frames[i].returnOffset = dbgFrames[i].ReturnOffset;
frames[i].frameOffset = dbgFrames[i].FrameOffset;
frames[i].stackOffset = dbgFrames[i].StackOffset;
}
}
///////////////////////////////////////////////////////////////////////////////
void getCurrentFrame(STACK_FRAME_DESC &frame )
{
PyThread_StateRestore pyThreadRestore( g_dbgEng->pystate );
HRESULT hres;
frame.number = 0;
hres = g_dbgEng->registers->GetInstructionOffset2( DEBUG_REGSRC_FRAME, &frame.instructionOffset );
if ( FAILED(hres) )
throw DbgException( "IDebugRegisters2::GetInstructionOffset2", hres );
hres = g_dbgEng->control->GetReturnOffset( &frame.returnOffset );
if ( FAILED(hres) )
throw DbgException( "IDebugControl::GetReturnOffset", hres );
hres = g_dbgEng->registers->GetFrameOffset2( DEBUG_REGSRC_FRAME, &frame.frameOffset );
if ( FAILED(hres) )
throw DbgException( "IDebugRegisters2::GetFrameOffset2", hres );
hres = g_dbgEng->registers->GetStackOffset2( DEBUG_REGSRC_FRAME, &frame.stackOffset );
if ( FAILED(hres) )
throw DbgException( "IDebugRegisters2::GetStackOffset2", hres );
}
///////////////////////////////////////////////////////////////////////////////
void getStackTrace(std::vector<STACK_FRAME_DESC> &frames)
{
PyThread_StateRestore pyThreadRestore( g_dbgEng->pystate );
frames.resize(0);
buildStacksFrames(frames);
}
///////////////////////////////////////////////////////////////////////////////
static void ReadWow64Context(WOW64_CONTEXT &Context)
{
//
// *** undoc ***
// !wow64exts.r
// http://www.woodmann.com/forum/archive/index.php/t-11162.html
// http://www.nynaeve.net/Code/GetThreadWow64Context.cpp
//
HRESULT hres;
ULONG debugClass, debugQualifier;
hres = g_dbgEng->control->GetDebuggeeType( &debugClass, &debugQualifier );
if ( FAILED( hres ) )
throw DbgException( "IDebugControl::GetDebuggeeType failed" );
ULONG64 teb64Address;
if ( debugClass == DEBUG_CLASS_KERNEL )
{
DEBUG_VALUE debugValue = {};
ULONG remainderIndex = 0;
hres = g_dbgEng->control->EvaluateWide(
L"@@C++(#FIELD_OFFSET(nt!_KTHREAD, Teb))",
DEBUG_VALUE_INT64,
&debugValue,
&remainderIndex );
if ( FAILED( hres ) )
throw DbgException( "IDebugControl::Evaluate failed" );
ULONG64 tebOffset = debugValue.I64;
hres = g_dbgEng->system->GetImplicitThreadDataOffset(&teb64Address);
if (S_OK != hres)
throw DbgException( "IDebugSystemObjects::GetImplicitThreadDataOffset", hres);
ULONG readedBytes;
readMemoryUnsafeNoSafe(
teb64Address + tebOffset,
&teb64Address,
sizeof(teb64Address),
false,
&readedBytes);
}
else
{
hres = g_dbgEng->system->GetImplicitThreadDataOffset(&teb64Address);
if (S_OK != hres)
throw DbgException( "IDebugSystemObjects::GetImplicitThreadDataOffset", hres);
}
// ? @@C++(#FIELD_OFFSET(nt!_TEB64, TlsSlots))
// hardcoded in !wow64exts.r (6.2.8250.0)
static const ULONG teb64ToTlsOffset = 0x01480;
static const ULONG WOW64_TLS_CPURESERVED = 1;
ULONG64 cpuAreaAddress;
ULONG readedBytes;
bool readRes;
readRes =
readMemoryUnsafeNoSafe(
teb64Address + teb64ToTlsOffset + (sizeof(ULONG64) * WOW64_TLS_CPURESERVED),
&cpuAreaAddress,
sizeof(cpuAreaAddress),
false,
&readedBytes);
if (!readRes || readedBytes != sizeof(cpuAreaAddress))
throw DbgException( "IDebugDataSpaces::ReadVirtual", hres);
// CPU Area is:
// +00 unknown ULONG
// +04 WOW64_CONTEXT struct
static const ULONG cpuAreaToWow64ContextOffset = sizeof(ULONG);
readRes =
readMemoryUnsafeNoSafe(
cpuAreaAddress + cpuAreaToWow64ContextOffset,
&Context,
sizeof(Context),
false,
&readedBytes);
if (!readRes || readedBytes != sizeof(Context))
throw DbgException( "IDebugDataSpaces::ReadVirtual", hres);
}
///////////////////////////////////////////////////////////////////////////////
class AutoRevertEffectiveProcessorType
{
public:
AutoRevertEffectiveProcessorType()
: m_processType(IMAGE_FILE_MACHINE_UNKNOWN)
{
}
~AutoRevertEffectiveProcessorType()
{
if (IMAGE_FILE_MACHINE_UNKNOWN != m_processType)
BOOST_VERIFY(S_OK == g_dbgEng->control->SetEffectiveProcessorType(m_processType));
}
void to(ULONG processType) { m_processType = processType; }
private:
ULONG m_processType;
};
///////////////////////////////////////////////////////////////////////////////
void getStackTraceWow64(std::vector<STACK_FRAME_DESC> &frames)
{
PyThread_StateRestore pyThreadRestore( g_dbgEng->pystate );
frames.resize(0);
ULONG processorType;
HRESULT hres = g_dbgEng->control->GetActualProcessorType(&processorType);
if (S_OK != hres)
throw DbgException( "IDebugControl::GetActualProcessorType", hres );
if (IMAGE_FILE_MACHINE_AMD64 != processorType)
throw DbgException( "Only for WOW64 processor mode" );
hres = g_dbgEng->control->GetEffectiveProcessorType(&processorType);
if (S_OK != hres)
throw DbgException( "IDebugControl::GetEffectiveProcessorType", hres );
WOW64_CONTEXT Context;
ReadWow64Context(Context);
AutoRevertEffectiveProcessorType autoRevertEffectiveProcessorType;
if (IMAGE_FILE_MACHINE_I386 != processorType)
{
if (IMAGE_FILE_MACHINE_AMD64 != processorType)
throw DbgException( "Only for WOW64 processor mode" );
hres = g_dbgEng->control->SetEffectiveProcessorType(IMAGE_FILE_MACHINE_I386);
if (S_OK != hres)
throw DbgException( "IDebugControl::SetEffectiveProcessorType", hres );
autoRevertEffectiveProcessorType.to(IMAGE_FILE_MACHINE_AMD64);
}
ULONG filledFrames = 1024;
std::vector<DEBUG_STACK_FRAME> dbgFrames(filledFrames);
hres = g_dbgEng->control->GetContextStackTrace(
&Context,
sizeof(Context),
&dbgFrames[0],
filledFrames,
NULL,
filledFrames*sizeof(Context),
sizeof(Context),
&filledFrames );
frames.resize(filledFrames);
for ( ULONG i = 0; i < filledFrames; ++i )
{
frames[i].number = dbgFrames[i].FrameNumber;
frames[i].instructionOffset = dbgFrames[i].InstructionOffset;
frames[i].returnOffset = dbgFrames[i].ReturnOffset;
frames[i].frameOffset = dbgFrames[i].FrameOffset;
frames[i].stackOffset = dbgFrames[i].StackOffset;
}
}
///////////////////////////////////////////////////////////////////////////////
std::string processorToStr(ULONG processorMode)
{
switch( processorMode )
{
case IMAGE_FILE_MACHINE_I386:
return "X86";
case IMAGE_FILE_MACHINE_ARM:
return "ARM";
case IMAGE_FILE_MACHINE_IA64:
return "IA64";
case IMAGE_FILE_MACHINE_AMD64:
return "X64";
}
throw DbgException( "Unknown CPU type" );
}
///////////////////////////////////////////////////////////////////////////////
std::string getProcessorMode()
{
PyThread_StateRestore pyThreadRestore( g_dbgEng->pystate );
HRESULT hres;
ULONG processorMode;
hres = g_dbgEng->control->GetEffectiveProcessorType( &processorMode );
if ( FAILED( hres ) )
throw DbgException( "IDebugControl::GetEffectiveProcessorType failed" );
return processorToStr(processorMode);
}
///////////////////////////////////////////////////////////////////////////////
void setProcessorMode( const std::string &mode )
{
HRESULT hres;
ULONG processorMode;
if ( mode == "X86" )
processorMode = IMAGE_FILE_MACHINE_I386;
else if ( mode == "ARM" )
processorMode = IMAGE_FILE_MACHINE_ARM;
else if ( mode == "IA64" )
processorMode = IMAGE_FILE_MACHINE_IA64;
else if ( mode == "X64" )
processorMode = IMAGE_FILE_MACHINE_AMD64;
else
throw DbgException( "Unknown processor type" );
hres = g_dbgEng->control->SetEffectiveProcessorType( processorMode );
if ( FAILED( hres ) )
throw DbgException( "IDebugControl::SetEffectiveProcessorType failed" );
}
///////////////////////////////////////////////////////////////////////////////
std::string getProcessorType()
{
PyThread_StateRestore pyThreadRestore( g_dbgEng->pystate );
HRESULT hres;
ULONG processorMode;
hres = g_dbgEng->control->GetActualProcessorType( &processorMode );
if ( FAILED( hres ) )
throw DbgException( "IDebugControl::GetActualProcessorType failed" );
return processorToStr(processorMode);
}
///////////////////////////////////////////////////////////////////////////////
ULONG breakPointSet( ULONG64 offset, bool hardware, ULONG size, ULONG accessType )
{
PyThread_StateRestore pyThreadRestore( g_dbgEng->pystate );
HRESULT hres;
IDebugBreakpoint *bp;
hres = g_dbgEng->control->AddBreakpoint(
hardware ? DEBUG_BREAKPOINT_DATA : DEBUG_BREAKPOINT_CODE,
DEBUG_ANY_ID,
&bp);
if (S_OK != hres)
throw DbgException("IDebugControl::AddBreakpoint", hres);
hres = bp->SetOffset(offset);
if (S_OK != hres)
{
g_dbgEng->control->RemoveBreakpoint(bp);
throw DbgException("IDebugBreakpoint::SetOffset", hres);
}
ULONG bpFlags;
hres = bp->GetFlags(&bpFlags);
if (S_OK != hres)
{
g_dbgEng->control->RemoveBreakpoint(bp);
throw DbgException("IDebugBreakpoint::GetFlags", hres);
}
if ( hardware )
{
HRESULT hres = bp->SetDataParameters(size, accessType);
if (S_OK != hres)
{
g_dbgEng->control->RemoveBreakpoint(bp);
throw DbgException("IDebugBreakpoint::SetDataParameters", hres);
}
}
bpFlags |= DEBUG_BREAKPOINT_ENABLED | DEBUG_BREAKPOINT_GO_ONLY;
hres = bp->SetFlags(bpFlags);
if (S_OK != hres)
{
g_dbgEng->control->RemoveBreakpoint(bp);
throw DbgException("IDebugBreakpoint::SetFlags", hres);
}
ULONG breakId;
hres = bp->GetId(&breakId);
if (S_OK != hres)
{
g_dbgEng->control->RemoveBreakpoint(bp);
throw DbgException("IDebugBreakpoint::GetId", hres);
}
return breakId;
}
///////////////////////////////////////////////////////////////////////////////
void breakPointRemove( ULONG id )
{
PyThread_StateRestore pyThreadRestore( g_dbgEng->pystate );
IDebugBreakpoint *bp;
HRESULT hres = g_dbgEng->control->GetBreakpointById(id, &bp);
if (S_OK != hres)
throw DbgException("IDebugControl::GetBreakpointById", hres);
hres = g_dbgEng->control->RemoveBreakpoint(bp);
if (S_OK != hres)
throw DbgException("IDebugControl::RemoveBreakpoint", hres);
}
///////////////////////////////////////////////////////////////////////////////
void breakPointRemoveAll()
{
PyThread_StateRestore pyThreadRestore( g_dbgEng->pystate );
ULONG numberOfBps;
do {
HRESULT hres = g_dbgEng->control->GetNumberBreakpoints(&numberOfBps);
if (S_OK != hres)
throw DbgException("IDebugControl::GetNumberBreakpoints", hres);
if (!numberOfBps)
break;
IDebugBreakpoint *bp;
hres = g_dbgEng->control->GetBreakpointByIndex(0, &bp);
if (S_OK != hres)
throw DbgException("IDebugControl::GetBreakpointByIndex", hres);
hres = g_dbgEng->control->RemoveBreakpoint(bp);
if (S_OK != hres)
throw DbgException("IDebugControl::RemoveBreakpoint", hres);
} while (numberOfBps);
}
///////////////////////////////////////////////////////////////////////////////
void eventRegisterCallbacks( const DEBUG_EVENT_CALLBACK *callbacks )
{
g_dbgEng.registerCallbacks( callbacks );
}
void DebugEngine::registerCallbacks( const DEBUG_EVENT_CALLBACK *callbacks )
{
boost::recursive_mutex::scoped_lock l(m_handlerLock);
m_handlers.push_back( DebugEventContext( callbacks, PyThreadStateSaver( PyThreadState_Get() ) ) );
}
///////////////////////////////////////////////////////////////////////////////
void eventRemoveCallbacks( const DEBUG_EVENT_CALLBACK *callback )
{
g_dbgEng.removeCallbacks( callback );
}
void DebugEngine::removeCallbacks( const DEBUG_EVENT_CALLBACK *callback )
{
boost::recursive_mutex::scoped_lock l(m_handlerLock);
HandlerList::iterator it = m_handlers.begin();
for ( ; it != m_handlers.end(); ++it )
{
if ( it->callback == callback )
{
m_handlers.erase( it );
break;
}
}
}
///////////////////////////////////////////////////////////////////////////////
inline
ULONG ConvertCallbackResult( DEBUG_CALLBACK_RESULT result )
{
switch( result )
{
case DebugCallbackBreak:
return DEBUG_STATUS_BREAK;
case DebugCallbackProceed:
return DEBUG_STATUS_GO_HANDLED;
default:
assert( 0 );
case DebugCallbackNoChange:
return DEBUG_STATUS_NO_CHANGE;
}
}
///////////////////////////////////////////////////////////////////////////////
HRESULT STDMETHODCALLTYPE DebugEngine::Breakpoint(
__in IDebugBreakpoint *bp
)
{
HRESULT hres;
ULONG id;
DEBUG_CALLBACK_RESULT result = DebugCallbackNoChange;
hres = bp->GetId( &id );
if ( FAILED( hres ) )
return DEBUG_STATUS_NO_CHANGE;
boost::recursive_mutex::scoped_lock l(m_handlerLock);
HandlerList::iterator it = m_handlers.begin();
for ( ; it != m_handlers.end(); ++it )
{
PyThread_StateSave pyThreadSave( it->pystate );
DEBUG_CALLBACK_RESULT ret = it->callback->OnBreakpoint( id );
result = ret != DebugCallbackNoChange ? ret : result;
}
return ConvertCallbackResult( result );
}
///////////////////////////////////////////////////////////////////////////////
HRESULT STDMETHODCALLTYPE DebugEngine::LoadModule(
__in ULONG64 ImageFileHandle,
__in ULONG64 BaseOffset,
__in ULONG ModuleSize,
__in_opt PCSTR ModuleName,
__in_opt PCSTR ImageName,
__in ULONG CheckSum,
__in ULONG TimeDateStamp
)
{
DEBUG_CALLBACK_RESULT result = DebugCallbackNoChange;
boost::recursive_mutex::scoped_lock l(m_handlerLock);
HandlerList::iterator it = m_handlers.begin();
for ( ; it != m_handlers.end(); ++it )
{
PyThread_StateSave pyThreadSave( it->pystate );
std::string modName;
if ( ModuleName )
{
modName = ModuleName;
}
else if ( ImageName )
{
// <20><><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> kernel <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> ModuleName <20><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD> NULL;
modName = ImageName;
modName.erase( modName.rfind('.') );
}
else
modName = "";
DEBUG_CALLBACK_RESULT ret = it->callback->OnModuleLoad( BaseOffset, modName );
result = ret != DebugCallbackNoChange ? ret : result;
}
return ConvertCallbackResult( result );
}
///////////////////////////////////////////////////////////////////////////////
HRESULT STDMETHODCALLTYPE DebugEngine::UnloadModule(
__in_opt PCSTR ImageBaseName,
__in ULONG64 BaseOffset )
{
DEBUG_CALLBACK_RESULT result = DebugCallbackNoChange;
HRESULT hres;
char moduleNameBuf[0x100];
// <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>, <20><><EFBFBD><EFBFBD><EFBFBD> <20><> BaseOffset <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20>. getModuleName
hres = g_dbgEng->symbols->GetModuleNameString(
DEBUG_MODNAME_MODULE,
DEBUG_ANY_ID,
BaseOffset,
moduleNameBuf,
sizeof( moduleNameBuf ),
NULL );
std::string moduleName = "";
if ( hres == S_OK )
moduleName = std::string( moduleNameBuf );
boost::recursive_mutex::scoped_lock l(m_handlerLock);
HandlerList::iterator it = m_handlers.begin();
for ( ; it != m_handlers.end(); ++it )
{
PyThread_StateSave pyThreadSave( it->pystate );
DEBUG_CALLBACK_RESULT ret = it->callback->OnModuleUnload( BaseOffset, moduleName );
result = ret != DebugCallbackNoChange ? ret : result;
}
return ConvertCallbackResult( result );
}
///////////////////////////////////////////////////////////////////////////////
HRESULT STDMETHODCALLTYPE DebugEngine::Exception(
__in PEXCEPTION_RECORD64 Exception,
__in ULONG FirstChance )
{
DEBUG_CALLBACK_RESULT result = DebugCallbackNoChange;
boost::recursive_mutex::scoped_lock l(m_handlerLock);
HandlerList::iterator it = m_handlers.begin();
for ( ; it != m_handlers.end(); ++it )
{
PyThread_StateSave pyThreadSave( it->pystate );
DEBUG_CALLBACK_RESULT ret = it->callback->OnException(
ExceptionInfoPtr( new ExceptionInfo(FirstChance, *Exception) )
);
result = ret != DebugCallbackNoChange ? ret : result;
}
return ConvertCallbackResult( result );
}
///////////////////////////////////////////////////////////////////////////////
HRESULT STDMETHODCALLTYPE DebugEngine::ChangeEngineState(
__in ULONG Flags,
__in ULONG64 Argument )
{
boost::recursive_mutex::scoped_lock l(m_handlerLock);
HandlerList::iterator it = m_handlers.begin();
if ( ( ( Flags & DEBUG_CES_EXECUTION_STATUS ) != 0 ) &&
( ( Argument & DEBUG_STATUS_INSIDE_WAIT ) == 0 ) &&
(ULONG)Argument != previousExecutionStatus )
{
for ( ; it != m_handlers.end(); ++it )
{
PyThread_StateSave pyThreadSave( it->pystate );
it->callback->onExecutionStatusChange( (ULONG)Argument );
}
previousExecutionStatus = (ULONG)Argument;
}
return S_OK;
}
///////////////////////////////////////////////////////////////////////////////
HRESULT STDMETHODCALLTYPE DebugEngine::ChangeSymbolState(
__in ULONG Flags,
__in ULONG64 Argument )
{
HandlerList::iterator it;
if (Flags & DEBUG_CSS_LOADS)
{
for ( it = m_handlers.begin(); it != m_handlers.end(); ++it )
{
PyThread_StateSave pyThreadSave( it->pystate );
it->callback->onSymbolsLoaded( Argument );
}
}
if (Flags & DEBUG_CSS_UNLOADS)
{
for ( it = m_handlers.begin(); it != m_handlers.end(); ++it )
{
PyThread_StateSave pyThreadSave( it->pystate );
it->callback->onSymbolsUnloaded( Argument );
}
}
return S_OK;
}
///////////////////////////////////////////////////////////////////////////////
HRESULT STDMETHODCALLTYPE DebugEngine::StartInput(
__in ULONG BufferSize )
{
std::string s = "";
{
PyThread_StateSave pyThreadSave( g_dbgEng->pystate );
python::object ret = python::eval( "raw_input(\"input>\")" );
s = python::extract<std::string>( ret );
}
g_dbgEng->control->ReturnInput ( s.c_str() );
return S_OK;
}
///////////////////////////////////////////////////////////////////////////////
HRESULT STDMETHODCALLTYPE DebugEngine::EndInput()
{
return S_OK;
}
///////////////////////////////////////////////////////////////////////////////
DebugEngine::DbgEngBind* DebugEngine::operator->()
{
if ( m_bind.get() != NULL )
return m_bind.get();
CComPtr<IDebugClient4> client = NULL;
HRESULT hres = DebugCreate( __uuidof(IDebugClient4), (void **)&client );
if ( FAILED( hres ) )
throw DbgException("DebugCreate failed");
m_bind.reset(new DbgEngBind(client, this) );
if ( !WindbgGlobalSession::isInit() )
{
python::object main = boost::python::import("__main__");
python::object main_namespace = main.attr("__dict__");
python::object pykd = boost::python::import( "pykd" );
main_namespace["globalEventHandler"] = EventHandlerPtr( new EventHandlerImpl() );
client->SetInputCallbacks( this );
}
return m_bind.get();
}
///////////////////////////////////////////////////////////////////////////////
ULONG64
getCurrentProcess()
{
PyThread_StateRestore pyThreadRestore( g_dbgEng->pystate );
HRESULT hres;
ULONG64 processAddr = 0;
hres = g_dbgEng->system->GetImplicitProcessDataOffset( &processAddr );
if ( FAILED( hres ) )
throw DbgException( "IDebugSystemObjects2::GetImplicitProcessDataOffset failed" );
return processAddr;
}
///////////////////////////////////////////////////////////////////////////////
ULONG getCurrentProcessId()
{
PyThread_StateRestore pyThreadRestore( g_dbgEng->pystate );
HRESULT hres;
ULONG pid;
hres = g_dbgEng->system->GetCurrentProcessSystemId( &pid );
if ( FAILED( hres ) )
throw DbgException( "IDebugSystemObjects2::GetCurrentProcessSystemId failed" );
return pid;
}
///////////////////////////////////////////////////////////////////////////////
ULONG64
getImplicitThread()
{
PyThread_StateRestore pyThreadRestore( g_dbgEng->pystate );
HRESULT hres;
ULONG64 threadOffset = -1;
hres = g_dbgEng->system->GetImplicitThreadDataOffset( &threadOffset );
if ( FAILED( hres ) )
throw DbgException( "IDebugSystemObjects2::GetImplicitThreadDataOffset failed" );
return threadOffset;
}
///////////////////////////////////////////////////////////////////////////////
ULONG getCurrentThreadId()
{
PyThread_StateRestore pyThreadRestore( g_dbgEng->pystate );
HRESULT hres;
ULONG tid;
hres = g_dbgEng->system->GetCurrentThreadSystemId( &tid );
if ( FAILED( hres ) )
throw DbgException( "IDebugSystemObjects2::GetCurrentThreadSystemId failed" );
return tid;
}
///////////////////////////////////////////////////////////////////////////////
void setCurrentProcess( ULONG64 processAddr )
{
PyThread_StateRestore pyThreadRestore( g_dbgEng->pystate );
HRESULT hres;
processAddr = addr64NoSafe(processAddr);
hres = g_dbgEng->system->SetImplicitProcessDataOffset( processAddr );
if ( FAILED( hres ) )
throw DbgException( "IDebugSystemObjects2::SetImplicitProcessDataOffset failed" );
}
///////////////////////////////////////////////////////////////////////////////
void setImplicitThread( ULONG64 threadAddr )
{
PyThread_StateRestore pyThreadRestore( g_dbgEng->pystate );
HRESULT hres;
threadAddr = addr64NoSafe(threadAddr);
hres = g_dbgEng->system->SetImplicitThreadDataOffset( threadAddr );
if ( FAILED( hres ) )
throw DbgException( "IDebugSystemObjects2::SetImplicitThreadDataOffset failed" );
}
///////////////////////////////////////////////////////////////////////////////
void getAllProcessThreads( std::vector<ULONG64> &threadsArray )
{
PyThread_StateRestore pyThreadRestore( g_dbgEng->pystate );
HRESULT hres;
ULONG debugClass, debugQualifier;
hres = g_dbgEng->control->GetDebuggeeType( &debugClass, &debugQualifier );
if ( FAILED( hres ) )
throw DbgException( "IDebugControl::GetDebuggeeType failed" );
if ( debugClass != DEBUG_CLASS_USER_WINDOWS )
throw DbgException( "getAllProcessThreads routine only for usermode" );
ULONG threadsNumber = 0;
hres = g_dbgEng->system->GetNumberThreads( &threadsNumber );
if ( FAILED(hres) )
throw DbgException( "IDebugSystemObjects::GetNumberThreads failed" );
std::vector<ULONG> ids(threadsNumber);
hres = g_dbgEng->system->GetThreadIdsByIndex( 0, threadsNumber, &ids[0], NULL );
if ( FAILED(hres) )
throw DbgException( "IDebugSystemObjects::GetThreadIdsByIndex failed" );
ULONG currentThreadId;
hres = g_dbgEng->system->GetCurrentThreadId( &currentThreadId );
if ( FAILED(hres) )
throw DbgException( "IDebugSystemObjects::GetCurrentThreadId failed" );
threadsArray.resize( threadsNumber );
for ( size_t i = 0; i < threadsNumber; ++i )
{
hres = g_dbgEng->system->SetCurrentThreadId( ids[i] );
if ( FAILED(hres) )
{
g_dbgEng->system->SetCurrentThreadId( currentThreadId );
throw DbgException( "IDebugSystemObjects::SetCurrentThreadId failed" );
}
hres = g_dbgEng->system->GetCurrentThreadTeb( &threadsArray[i] );
if ( FAILED(hres) )
{
g_dbgEng->system->SetCurrentThreadId( currentThreadId );
throw DbgException( "IDebugSystemObjects::GetCurrentThreadTeb failed" );
}
}
g_dbgEng->system->SetCurrentThreadId( currentThreadId );
}
///////////////////////////////////////////////////////////////////////////////
ULONG64 loadExtension(const std::wstring &extPath )
{
PyThread_StateRestore pyThreadRestore( g_dbgEng->pystate );
HRESULT hres;
ULONG64 handle = 0;
hres = g_dbgEng->control->AddExtensionWide( extPath.c_str(), 0, &handle );
if ( FAILED( hres ) )
throw DbgException( "IDebugControl::AddExtension failed" );
return handle;
}
///////////////////////////////////////////////////////////////////////////////
void removeExtension( ULONG64 extHandle )
{
PyThread_StateRestore pyThreadRestore( g_dbgEng->pystate );
g_dbgEng->control->RemoveExtension( extHandle );
}
///////////////////////////////////////////////////////////////////////////////
std::string callExtension( ULONG64 extHandle, const std::wstring command, const std::wstring &params )
{
PyThread_StateRestore pyThreadRestore( g_dbgEng->pystate );
HRESULT hres;
OutputReader outReader( g_dbgEng->client );
hres = g_dbgEng->control->CallExtensionWide( extHandle, command.c_str(), params.c_str() );
if ( FAILED( hres ) )
throw DbgException( "IDebugControl::CallExtension failed" );
return std::string( outReader.Line() );
}
///////////////////////////////////////////////////////////////////////////////
} // end pykd namespace