413 lines
11 KiB
ObjectPascal
413 lines
11 KiB
ObjectPascal
unit NetworkDebuggerInterface;
|
|
|
|
{$mode delphi}
|
|
|
|
interface
|
|
|
|
uses
|
|
|
|
{$ifdef windows}
|
|
jwawindows, windows,
|
|
{$endif}
|
|
Classes, SysUtils,cefuncproc, newkernelhandler,
|
|
DebuggerInterface, networkInterface, networkInterfaceApi, contnrs{$ifdef darwin},macport, macportdefines{$endif};
|
|
|
|
type
|
|
TNetworkDebuggerInterface=class(TDebuggerInterface)
|
|
private
|
|
handle: THandle;
|
|
lastevent: TNetworkDebugEvent;
|
|
fsinglestepNextContinue: boolean;
|
|
|
|
public
|
|
function WaitForDebugEvent(var lpDebugEvent: TDebugEvent; dwMilliseconds: DWORD): BOOL; override;
|
|
function ContinueDebugEvent(dwProcessId: DWORD; dwThreadId: DWORD; dwContinueStatus: DWORD): BOOL; override;
|
|
function SetThreadContext(hThread: THandle; const lpContext: TContext; isFrozenThread: Boolean=false): BOOL; override;
|
|
function GetThreadContext(hThread: THandle; var lpContext: TContext; isFrozenThread: Boolean=false): BOOL; override;
|
|
|
|
function SetThreadContextArm(hThread: THandle; const lpContext: TArmContext; isFrozenThread: Boolean=false): BOOL; override;
|
|
function GetThreadContextArm(hThread: THandle; var lpContext: TArmContext; isFrozenThread: Boolean=false): BOOL; override;
|
|
|
|
|
|
function GetLastBranchRecords(lbr: pointer): integer; override;
|
|
function canReportExactDebugRegisterTrigger: boolean; override;
|
|
|
|
function DebugActiveProcess(dwProcessId: DWORD): WINBOOL; override;
|
|
property SingleStepNextContinue: boolean read fSingleStepNextContinue write fSingleStepNextContinue;
|
|
|
|
destructor destroy; override;
|
|
constructor create;
|
|
end;
|
|
|
|
|
|
implementation
|
|
|
|
uses debuggertypedefinitions, ProcessHandlerUnit;
|
|
|
|
type
|
|
TNetworkX86_32Context=packed record
|
|
ebx: dword;
|
|
ecx: dword;
|
|
edx: dword;
|
|
esi: dword;
|
|
edi: dword;
|
|
ebp: dword;
|
|
eax: dword;
|
|
ds: integer;
|
|
es: integer;
|
|
fs: integer;
|
|
gs: integer;
|
|
orig_eax: dword;
|
|
eip: dword;
|
|
cs: integer;
|
|
eflags: dword;
|
|
esp: dword;
|
|
ss: integer;
|
|
end;
|
|
|
|
PNetworkX86_32Context=^TNetworkX86_32Context;
|
|
|
|
TNetworkX86_64Context=packed record
|
|
r15: qword;
|
|
r14: qword;
|
|
r13: qword;
|
|
r12: qword;
|
|
rbp: qword;
|
|
rbx: qword;
|
|
r11: qword;
|
|
r10: qword;
|
|
r9: qword;
|
|
r8: qword;
|
|
rax: qword;
|
|
rcx: qword;
|
|
rdx: qword;
|
|
rsi: qword;
|
|
rdi: qword;
|
|
orig_rax: qword;
|
|
rip: qword;
|
|
cs: qword;
|
|
eflags: qword;
|
|
rsp: qword;
|
|
ss: qword;
|
|
fs_base: qword;
|
|
gs_base: qword;
|
|
ds: qword;
|
|
es: qword;
|
|
fs: qword;
|
|
gs: qword;
|
|
end;
|
|
PNetworkX86_64Context=^TNetworkX86_64Context;
|
|
|
|
|
|
TNetworkArmContext=packed record
|
|
R0: DWORD;
|
|
R1: DWORD;
|
|
R2: DWORD;
|
|
R3: DWORD;
|
|
R4: DWORD;
|
|
R5: DWORD;
|
|
R6: DWORD;
|
|
R7: DWORD;
|
|
R8: DWORD;
|
|
R9: DWORD;
|
|
R10: DWORD;
|
|
FP: DWORD;
|
|
IP: DWORD;
|
|
SP: DWORD;
|
|
LR: DWORD;
|
|
PC: DWORD;
|
|
CPSR: DWORD;
|
|
ORIG_R0: DWORD;
|
|
end;
|
|
|
|
PNetworkArmContext=^TNetworkArmContext;
|
|
|
|
|
|
function TNetworkDebuggerInterface.WaitForDebugEvent(var lpDebugEvent: TDebugEvent; dwMilliseconds: DWORD): BOOL;
|
|
var
|
|
c: TCEConnection;
|
|
begin
|
|
|
|
result:=false;
|
|
c:=getConnection;
|
|
if c<>nil then
|
|
begin
|
|
lastevent.signal:=5;
|
|
|
|
result:=c.WaitForDebugEvent(handle, dwMilliseconds*5, lastevent);
|
|
|
|
if result then
|
|
begin
|
|
//convert it to 'something' useful
|
|
lpDebugEvent.dwThreadId:=lastevent.threadid;
|
|
lpDebugEvent.dwProcessId:=processid;
|
|
|
|
case lastevent.signal of
|
|
-1 : //create thread
|
|
begin
|
|
lpDebugEvent.dwDebugEventCode:=CREATE_THREAD_DEBUG_EVENT;
|
|
lpDebugEvent.CreateThread.hThread:=lastevent.threadid;
|
|
end;
|
|
|
|
-2 : //create process
|
|
begin
|
|
lpDebugEvent.dwDebugEventCode:=CREATE_PROCESS_DEBUG_EVENT;
|
|
lpDebugEvent.CreateProcessInfo.hProcess:=handle;
|
|
lpDebugEvent.CreateProcessInfo.hThread:=lastevent.threadid;
|
|
|
|
//set the breakpoint capability
|
|
fmaxInstructionBreakpointCount:=lastevent.createProcess.maxBreakpointCount;
|
|
fmaxWatchpointBreakpointCount:=lastevent.createProcess.maxWatchpointCount;
|
|
fmaxSharedBreakpointCount:=lastevent.createProcess.maxSharedBreakpoints;
|
|
end;
|
|
|
|
5: //SIGTRAP
|
|
begin
|
|
lpDebugEvent.dwDebugEventCode:=EXCEPTION_DEBUG_EVENT;
|
|
lpDebugEvent.Exception.dwFirstChance:=1;
|
|
lpDebugEvent.Exception.ExceptionRecord.NumberParameters:=0;
|
|
|
|
lpDebugEvent.Exception.ExceptionRecord.ExceptionCode:=EXCEPTION_SINGLE_STEP;
|
|
lpDebugEvent.Exception.ExceptionRecord.ExceptionAddress:=pointer(lastevent.address);
|
|
|
|
end;
|
|
|
|
19: //sigstop
|
|
begin
|
|
//just ignore. continue and return that no stop happened (timeout)
|
|
ContinueDebugEvent(handle, lastevent.threadid, DBG_CONTINUE);
|
|
result:=false;
|
|
end;
|
|
|
|
|
|
|
|
else
|
|
begin
|
|
//no idea
|
|
|
|
ContinueDebugEvent(handle, lastevent.threadid, DBG_EXCEPTION_NOT_HANDLED);
|
|
result:=false;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
end;
|
|
|
|
function TNetworkDebuggerInterface.ContinueDebugEvent(dwProcessId: DWORD; dwThreadId: DWORD; dwContinueStatus: DWORD): BOOL;
|
|
var
|
|
c: TCEConnection;
|
|
begin
|
|
|
|
result:=false;
|
|
c:=getConnection;
|
|
if c<>nil then
|
|
begin
|
|
if dwContinueStatus=DBG_CONTINUE then
|
|
begin
|
|
if fSingleStepNextContinue then
|
|
result:=c.ContinueDebugEvent(handle, dwThreadID, 2) //ignore this signal and enter a single step mode
|
|
else
|
|
result:=c.ContinueDebugEvent(handle, dwThreadID, 1); //ignore this signal
|
|
|
|
fSingleStepNextContinue:=false;
|
|
end
|
|
else
|
|
result:=c.ContinueDebugEvent(handle, dwThreadID, 0);
|
|
end;
|
|
|
|
end;
|
|
|
|
function TNetworkDebuggerInterface.SetThreadContextArm(hThread: THandle; const lpContext: TArmContext; isFrozenThread: Boolean=false): BOOL;
|
|
//get the current context and apply the changes from this context
|
|
begin
|
|
result:=false;
|
|
end;
|
|
|
|
function TNetworkDebuggerInterface.GetThreadContextArm(hThread: THandle; var lpContext: TArmContext; isFrozenThread: Boolean=false): BOOL;
|
|
var
|
|
carm: PNetworkArmContext;
|
|
c: TCEConnection=nil;
|
|
begin
|
|
result:=false;
|
|
|
|
c:=getConnection;
|
|
if c<>nil then
|
|
begin
|
|
carm:=c.AllocateAndGetContext(handle, hThread);
|
|
|
|
|
|
if (carm<>nil) and (processhandler.SystemArchitecture=archARM) then
|
|
begin
|
|
if processhandler.is64Bit then
|
|
begin
|
|
lpContext.PC:=$64646464; //holder for 64 bit for now
|
|
end
|
|
else
|
|
begin
|
|
lpContext.R0:=carm.R0;
|
|
lpContext.R1:=carm.R1;
|
|
lpContext.R2:=carm.R2;
|
|
lpContext.R3:=carm.R3;
|
|
lpContext.R4:=carm.R4;
|
|
lpContext.R5:=carm.R5;
|
|
lpContext.R6:=carm.R6;
|
|
lpContext.R7:=carm.R7;
|
|
lpContext.R8:=carm.R8;
|
|
lpContext.R9:=carm.R9;
|
|
lpContext.R10:=carm.R10;
|
|
lpContext.FP:=carm.FP;
|
|
lpContext.IP:=carm.IP;
|
|
lpContext.SP:=carm.SP;
|
|
lpContext.LR:=carm.LR;
|
|
lpContext.PC:=carm.PC;
|
|
lpContext.CPSR:=carm.CPSR;
|
|
lpContext.ORIG_R0:=carm.ORIG_R0;
|
|
end;
|
|
end; //else use GetThreadContext
|
|
|
|
if (carm<>nil) then
|
|
FreeMemAndNil(carm);
|
|
end;
|
|
end;
|
|
|
|
|
|
|
|
function TNetworkDebuggerInterface.SetThreadContext(hThread: THandle; const lpContext: TContext; isFrozenThread: Boolean=false): BOOL;
|
|
begin
|
|
//get the current context and apply the changes from this context
|
|
result:=false;
|
|
end;
|
|
|
|
function TNetworkDebuggerInterface.GetThreadContext(hThread: THandle; var lpContext: TContext; isFrozenThread: Boolean=false): BOOL;
|
|
var
|
|
c32: PNetworkX86_32Context=nil;
|
|
c64: PNetworkX86_64Context absolute c32;
|
|
|
|
c: TCEConnection=nil;
|
|
begin
|
|
result:=false;
|
|
|
|
zeromemory(@lpContext, sizeof(TContext));
|
|
|
|
c:=getConnection;
|
|
if c<>nil then
|
|
begin
|
|
c32:=c.AllocateAndGetContext(handle, hThread);
|
|
|
|
|
|
if (c32<>nil) and (processhandler.SystemArchitecture=archX86) then
|
|
begin
|
|
{$ifdef cpu64}
|
|
if processhandler.is64Bit then
|
|
begin
|
|
lpcontext.r15:=c64.r15;
|
|
lpcontext.r14:=c64.r14;
|
|
lpcontext.r13:=c64.r13;
|
|
lpcontext.r12:=c64.r12;
|
|
lpcontext.rbp:=c64.rbp;
|
|
lpcontext.Rbx:=c64.rbx;
|
|
lpcontext.R11:=c64.r11;
|
|
lpcontext.R10:=c64.r10;
|
|
lpcontext.R9:=c64.r9;
|
|
lpcontext.R8:=c64.r8;
|
|
lpcontext.Rax:=c64.rax;
|
|
lpcontext.Rcx:=c64.rcx;
|
|
lpcontext.Rdx:=c64.rdx;
|
|
lpcontext.Rsi:=c64.rsi;
|
|
lpcontext.Rdi:=c64.rdi;
|
|
|
|
lpcontext.P1Home:=c64.orig_rax;
|
|
lpcontext.rip:=c64.rip;
|
|
lpcontext.SegCs:=c64.cs;
|
|
lpcontext.EFlags:=c64.eflags;
|
|
lpcontext.rsp:=c64.rsp;
|
|
lpcontext.Segss:=c64.ss;
|
|
lpcontext.P2Home:=c64.fs_base;
|
|
lpcontext.P3Home:=c64.gs_base;
|
|
lpcontext.Segds:=c64.ds;
|
|
lpcontext.Seges:=c64.es;
|
|
lpcontext.Segfs:=c64.fs;
|
|
lpcontext.Seggs:=c64.gs;
|
|
end
|
|
else
|
|
{$endif}
|
|
begin
|
|
lpcontext.{$ifdef cpu64}rbx{$else}ebx{$endif}:=c32.ebx;
|
|
lpcontext.{$ifdef cpu64}rcx{$else}ecx{$endif}:=c32.ecx;
|
|
lpcontext.{$ifdef cpu64}rdx{$else}edx{$endif}:=c32.edx;
|
|
lpcontext.{$ifdef cpu64}rsi{$else}esi{$endif}:=c32.esi;
|
|
lpcontext.{$ifdef cpu64}rdi{$else}edi{$endif}:=c32.edi;
|
|
lpcontext.{$ifdef cpu64}rbp{$else}ebp{$endif}:=c32.ebp;
|
|
lpcontext.{$ifdef cpu64}rax{$else}eax{$endif}:=c32.eax;
|
|
lpcontext.segds:=c32.ds;
|
|
lpcontext.seges:=c32.es;
|
|
lpcontext.segfs:=c32.fs;
|
|
lpcontext.seggs:=c32.gs;
|
|
|
|
lpcontext.{$ifdef cpu64}rip{$else}eip{$endif}:=c32.eip;
|
|
lpcontext.segcs:=c32.cs;
|
|
lpcontext.EFlags:=c32.eflags;
|
|
lpcontext.{$ifdef cpu64}rsp{$else}esp{$endif}:=c32.esp;
|
|
lpcontext.segss:=c32.ss;
|
|
end;
|
|
end; //you should use GetThreadContextArm
|
|
|
|
if c32<>nil then
|
|
FreeMemAndNil(c32);
|
|
end;
|
|
|
|
result:=lpContext.{$ifdef cpu64}rip{$else}eip{$endif}<>0;
|
|
end;
|
|
|
|
|
|
function TNetworkDebuggerInterface.GetLastBranchRecords(lbr: pointer): integer;
|
|
begin
|
|
result:=0;
|
|
end;
|
|
|
|
function TNetworkDebuggerInterface.DebugActiveProcess(dwProcessId: DWORD): WINBOOL;
|
|
var c: TCEConnection;
|
|
begin
|
|
result:=false;
|
|
processhandler.processid:=dwProcessID;
|
|
Open_Process;
|
|
|
|
handle:=ProcessHandle;
|
|
|
|
if (handle<>0) then
|
|
begin
|
|
c:=getConnection;
|
|
if c<>nil then
|
|
result:=c.StartDebug(handle);
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
function TNetworkDebuggerInterface.canReportExactDebugRegisterTrigger: boolean;
|
|
begin
|
|
result:=false;
|
|
end;
|
|
|
|
|
|
destructor TNetworkDebuggerInterface.destroy;
|
|
begin
|
|
|
|
{
|
|
if (handle)
|
|
networkStopDebug();
|
|
}
|
|
inherited destroy;
|
|
end;
|
|
|
|
constructor TNetworkDebuggerInterface.create;
|
|
begin
|
|
//no software breakpoint for now
|
|
fDebuggerCapabilities:=[dbcHardwareBreakpoint];
|
|
end;
|
|
|
|
|
|
end.
|
|
|