mirror of
https://github.com/cheat-engine/cheat-engine
synced 2026-08-15 02:26:08 -04:00
910 lines
24 KiB
ObjectPascal
910 lines
24 KiB
ObjectPascal
unit frmThreadlistunit;
|
|
|
|
{$MODE Delphi}
|
|
|
|
interface
|
|
|
|
uses
|
|
jwawindows, windows, LCLIntf, Messages, SysUtils, Classes, Graphics, Controls, Forms,
|
|
Dialogs, ComCtrls, Menus, StdCtrls, LResources,cefuncproc, CEDebugger, debugHelper,
|
|
newkernelhandler, networkInterface, networkInterfaceApi;
|
|
|
|
|
|
|
|
|
|
type
|
|
|
|
{ TfrmThreadlist }
|
|
|
|
TfrmThreadlist = class(TForm)
|
|
lblIsWOW64: TLabel;
|
|
MenuItem1: TMenuItem;
|
|
miClearDebugRegisters: TMenuItem;
|
|
miFreezeThread: TMenuItem;
|
|
miResumeThread: TMenuItem;
|
|
PopupMenu1: TPopupMenu;
|
|
miBreak: TMenuItem;
|
|
threadTreeview: TTreeView;
|
|
procedure FormClose(Sender: TObject; var Action: TCloseAction);
|
|
procedure FormCreate(Sender: TObject);
|
|
procedure FormShow(Sender: TObject);
|
|
procedure MenuItem1Click(Sender: TObject);
|
|
procedure miBreakClick(Sender: TObject);
|
|
procedure miClearDebugRegistersClick(Sender: TObject);
|
|
procedure miFreezeThreadClick(Sender: TObject);
|
|
procedure miResumeThreadClick(Sender: TObject);
|
|
procedure threadTreeviewDblClick(Sender: TObject);
|
|
procedure threadTreeviewExpanding(Sender: TObject; Node: TTreeNode;
|
|
var AllowExpansion: Boolean);
|
|
private
|
|
{ Private declarations }
|
|
public
|
|
{ Public declarations }
|
|
procedure FillThreadlist;
|
|
end;
|
|
|
|
var
|
|
frmThreadlist: TfrmThreadlist;
|
|
|
|
implementation
|
|
|
|
uses debugeventhandler, frmstacktraceunit, DebuggerInterfaceAPIWrapper,
|
|
ProcessHandlerUnit, Parsers;
|
|
|
|
resourcestring
|
|
rsPleaseFirstAttachTheDebuggerToThisProcess = 'Please first attach the debugger to this process';
|
|
rsCouldnTObtainContext = 'Couldn''t obtain context';
|
|
rsCouldnTOpenHandle = 'Couldn''t open handle';
|
|
rsTLChangeValue = 'Change value';
|
|
rsTLWhatShouldTheNewValueOfThisRegisterBe = 'What should the new value of this register be?';
|
|
rsTLFailedErrorcode = 'failed. Errorcode=';
|
|
rsTLExecute = 'Execute';
|
|
rsTLWrite = 'Write';
|
|
rsTLIO = 'I/O';
|
|
rsTLAccess = 'Access';
|
|
rsTL1Bytes = '1 byte';
|
|
rsTL2Bytes = '2 bytes';
|
|
rsTL8Bytes = '8 bytes';
|
|
rsTL4Bytes = '4 bytes';
|
|
|
|
procedure TfrmThreadlist.FormClose(Sender: TObject;
|
|
var Action: TCloseAction);
|
|
begin
|
|
action:=cafree;
|
|
frmthreadlist:=nil;
|
|
end;
|
|
|
|
procedure TfrmThreadlist.FormCreate(Sender: TObject);
|
|
begin
|
|
fillthreadlist;
|
|
end;
|
|
|
|
procedure TfrmThreadlist.FormShow(Sender: TObject);
|
|
begin
|
|
lblIsWOW64.visible:={$ifdef cpu64}processhandler.is64Bit=false{$else}false{$endif};
|
|
end;
|
|
|
|
procedure TfrmThreadlist.MenuItem1Click(Sender: TObject);
|
|
var
|
|
c: TCONTEXT;
|
|
{$ifdef cpu64}
|
|
c32: TContext32;
|
|
{$endif}
|
|
i: integer;
|
|
s: TTreeNode;
|
|
threadlist: tlist;
|
|
|
|
tid: dword;
|
|
th: THandle;
|
|
begin
|
|
|
|
zeromemory(@c, sizeof(c));
|
|
c.ContextFlags:=CONTEXT_FULL;
|
|
s:=threadTreeview.Selected;
|
|
if s<>nil then
|
|
begin
|
|
|
|
|
|
while s.level>0 do
|
|
s:=s.Parent;
|
|
|
|
tid:=strtoint('$'+s.Text);
|
|
|
|
if frmstacktrace=nil then
|
|
frmstacktrace:=tfrmstacktrace.create(application);
|
|
|
|
|
|
if debuggerthread<>nil then
|
|
begin
|
|
threadlist:=debuggerthread.lockThreadlist;
|
|
try
|
|
for i:=0 to threadlist.Count-1 do
|
|
begin
|
|
if TDebugThreadHandler(threadlist[i]).ThreadId=tid then
|
|
begin
|
|
{$ifdef cpu64}
|
|
if processhandler.is64Bit=false then
|
|
begin
|
|
ZeroMemory(@c32, sizeof(c32));
|
|
c32.ContextFlags:=CONTEXT_FULL;
|
|
Wow64GetThreadContext(TDebugThreadHandler(threadlist[i]).handle, c32);
|
|
c.Rip:=c32.Eip;
|
|
c.Rsp:=c32.esp;
|
|
c.Rbp:=c32.ebp;
|
|
end
|
|
else
|
|
{$endif}
|
|
GetThreadContext(TDebugThreadHandler(threadlist[i]).handle, c);
|
|
break;
|
|
end;
|
|
end;
|
|
finally
|
|
debuggerthread.unlockThreadlist;
|
|
end;
|
|
end
|
|
else
|
|
begin
|
|
th:=OpenThread(THREAD_GET_CONTEXT, false, tid);
|
|
|
|
if th<>0 then
|
|
begin
|
|
{$ifdef cpu64}
|
|
if processhandler.is64Bit=false then
|
|
begin
|
|
ZeroMemory(@c32, sizeof(c32));
|
|
c32.ContextFlags:=CONTEXT_FULL; ;
|
|
Wow64GetThreadContext(th, c32);
|
|
c.Rip:=c32.Eip;
|
|
c.Rsp:=c32.esp;
|
|
c.Rbp:=c32.ebp;
|
|
end
|
|
else
|
|
{$endif}
|
|
GetThreadContext(th, c);
|
|
|
|
closehandle(th);
|
|
end;
|
|
end;
|
|
|
|
|
|
frmstacktrace.stacktrace(th, c);
|
|
|
|
frmstacktrace.Show;
|
|
end;
|
|
|
|
|
|
|
|
|
|
end;
|
|
|
|
procedure TFrmthreadlist.FillThreadlist;
|
|
|
|
var i: integer;
|
|
lastselected: integer;
|
|
threadlist: tlist;
|
|
li: TListitem;
|
|
|
|
ths: THandle;
|
|
te32: TThreadEntry32;
|
|
p: PSystemProcesses;
|
|
needed: dword;
|
|
|
|
pp: PSystemProcesses;
|
|
begin
|
|
if threadTreeview.Selected<>nil then
|
|
lastselected:=threadTreeview.selected.index
|
|
else
|
|
lastselected:=-1;
|
|
|
|
threadTreeview.BeginUpdate;
|
|
threadTreeview.Items.Clear;
|
|
|
|
if debuggerthread<>nil then
|
|
begin
|
|
threadlist:=debuggerthread.lockThreadlist;
|
|
try
|
|
for i:=0 to threadlist.Count-1 do
|
|
threadTreeview.Items.Add(nil,inttohex(TDebugThreadHandler(threadlist[i]).ThreadId,1));
|
|
|
|
finally
|
|
debuggerthread.unlockThreadlist;
|
|
end;
|
|
end
|
|
else
|
|
begin
|
|
//get the list using thread32first/next
|
|
ths:=CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD,0);
|
|
if ths<>INVALID_HANDLE_VALUE then
|
|
begin
|
|
zeromemory(@te32,sizeof(te32));
|
|
te32.dwSize:=sizeof(te32);
|
|
if Thread32First(ths, te32) then
|
|
repeat
|
|
if te32.th32OwnerProcessID=processid then
|
|
threadTreeview.Items.add(nil,inttohex(te32.th32ThreadID,1));
|
|
|
|
until Thread32Next(ths, te32)=false;
|
|
closehandle(ths);
|
|
end;
|
|
|
|
|
|
|
|
end;
|
|
|
|
for i:=0 to threadTreeview.Items.Count-1 do
|
|
threadTreeview.Items[i].HasChildren:=true;
|
|
|
|
if (lastselected<>-1) and (threadTreeview.Items.Count>lastselected) then
|
|
threadTreeview.Items[lastselected].Selected:=true;
|
|
|
|
threadTreeview.EndUpdate;
|
|
end;
|
|
|
|
procedure TfrmThreadlist.miBreakClick(Sender: TObject);
|
|
var threadlist: tlist;
|
|
i: integer;
|
|
begin
|
|
if debuggerthread<>nil then
|
|
begin
|
|
if (threadTreeview.Selected<>nil) and (threadTreeview.selected.Level=0) then
|
|
begin
|
|
threadlist:=debuggerthread.lockThreadlist;
|
|
try
|
|
for i:=0 to threadlist.Count-1 do
|
|
begin
|
|
if TDebugThreadHandler(threadlist[i]).ThreadId=strtoint('$'+threadTreeview.selected.Text) then
|
|
begin
|
|
TDebugThreadHandler(threadlist[i]).breakThread;
|
|
break;
|
|
end;
|
|
end;
|
|
finally
|
|
debuggerthread.unlockThreadlist;
|
|
end;
|
|
|
|
end;
|
|
|
|
end
|
|
else
|
|
raise exception.create(rsPleaseFirstAttachTheDebuggerToThisProcess);
|
|
|
|
end;
|
|
|
|
procedure TfrmThreadlist.miClearDebugRegistersClick(Sender: TObject);
|
|
var threadlist: tlist;
|
|
i,j: integer;
|
|
s: ttreenode;
|
|
begin
|
|
if debuggerthread<>nil then
|
|
begin
|
|
for j:=0 to threadTreeview.SelectionCount-1 do
|
|
begin
|
|
s:=threadTreeview.Selections[j];
|
|
|
|
// if (threadTreeview.Selected<>nil) then
|
|
begin
|
|
//s:=threadTreeview.Selected;
|
|
while s.level>0 do
|
|
s:=s.parent;
|
|
|
|
|
|
threadlist:=debuggerthread.lockThreadlist;
|
|
try
|
|
for i:=0 to threadlist.Count-1 do
|
|
begin
|
|
if TDebugThreadHandler(threadlist[i]).ThreadId=strtoint('$'+s.Text) then
|
|
begin
|
|
TDebugThreadHandler(threadlist[i]).clearDebugRegisters;
|
|
break;
|
|
end;
|
|
end;
|
|
finally
|
|
debuggerthread.unlockThreadlist;
|
|
end;
|
|
end;
|
|
|
|
end;
|
|
|
|
end
|
|
else
|
|
raise exception.create(rsPleaseFirstAttachTheDebuggerToThisProcess);
|
|
end;
|
|
|
|
procedure TfrmThreadlist.miFreezeThreadClick(Sender: TObject);
|
|
var
|
|
i: integer;
|
|
s: TTreeNode;
|
|
threadlist: tlist;
|
|
|
|
tid: dword;
|
|
th: THandle;
|
|
begin
|
|
s:=threadTreeview.Selected;
|
|
if s<>nil then
|
|
begin
|
|
|
|
while s.level>0 do
|
|
s:=s.Parent;
|
|
|
|
tid:=strtoint('$'+s.Text);
|
|
|
|
if debuggerthread<>nil then
|
|
begin
|
|
threadlist:=debuggerthread.lockThreadlist;
|
|
try
|
|
for i:=0 to threadlist.Count-1 do
|
|
begin
|
|
if TDebugThreadHandler(threadlist[i]).ThreadId=tid then
|
|
begin
|
|
SuspendThread(TDebugThreadHandler(threadlist[i]).handle);
|
|
break;
|
|
end;
|
|
end;
|
|
finally
|
|
debuggerthread.unlockThreadlist;
|
|
end;
|
|
end
|
|
else
|
|
begin
|
|
th:=OpenThread(THREAD_SUSPEND_RESUME, false, tid);
|
|
|
|
if th<>0 then
|
|
begin
|
|
SuspendThread(th);
|
|
closehandle(th);
|
|
end;
|
|
end;
|
|
|
|
end;
|
|
end;
|
|
|
|
procedure TfrmThreadlist.miResumeThreadClick(Sender: TObject);
|
|
var
|
|
i: integer;
|
|
s: TTreeNode;
|
|
threadlist: tlist;
|
|
|
|
tid: dword;
|
|
th: Thandle;
|
|
begin
|
|
s:=threadTreeview.Selected;
|
|
if s<>nil then
|
|
begin
|
|
|
|
while s.level>0 do
|
|
s:=s.Parent;
|
|
|
|
tid:=strtoint('$'+s.Text);
|
|
|
|
if debuggerthread<>nil then
|
|
begin
|
|
threadlist:=debuggerthread.lockThreadlist;
|
|
try
|
|
for i:=0 to threadlist.Count-1 do
|
|
begin
|
|
if TDebugThreadHandler(threadlist[i]).ThreadId=tid then
|
|
begin
|
|
SuspendThread(TDebugThreadHandler(threadlist[i]).handle);
|
|
break;
|
|
end;
|
|
end;
|
|
finally
|
|
debuggerthread.unlockThreadlist;
|
|
end;
|
|
end
|
|
else
|
|
begin
|
|
th:=OpenThread(THREAD_SUSPEND_RESUME, false, tid);
|
|
|
|
if th<>0 then
|
|
begin
|
|
ResumeThread(th);
|
|
closehandle(th);
|
|
end;
|
|
end;
|
|
|
|
end;
|
|
end;
|
|
|
|
procedure TfrmThreadlist.threadTreeviewDblClick(Sender: TObject);
|
|
var s: TTreeNode;
|
|
th: thandle;
|
|
c: tcontext;
|
|
|
|
|
|
regnr: integer;
|
|
|
|
regaddress: PPtrUInt;
|
|
|
|
v: ptruint;
|
|
|
|
input: string;
|
|
tid: dword;
|
|
|
|
ai: integer;
|
|
x: boolean;
|
|
{$ifdef cpu64}
|
|
use32bitcontext: boolean;
|
|
c32: TContext32;
|
|
{$endif}
|
|
begin
|
|
//change the selected register
|
|
|
|
|
|
s:=threadTreeview.Selected;
|
|
if (s<>nil) and (s.level=1) then //selected a registers
|
|
begin
|
|
regnr:=s.Index;
|
|
ai:=s.AbsoluteIndex;
|
|
|
|
while s.level>0 do
|
|
s:=s.Parent;
|
|
|
|
tid:=strtoint('$'+s.Text);
|
|
|
|
|
|
|
|
|
|
th:=OpenThread(THREAD_SUSPEND_RESUME or THREAD_GET_CONTEXT or THREAD_SET_CONTEXT or THREAD_QUERY_INFORMATION, false, tid);
|
|
|
|
if th<>0 then
|
|
begin
|
|
suspendthread(th);
|
|
|
|
x:=false;
|
|
ZeroMemory(@c, sizeof(c));
|
|
|
|
{$ifdef cpu64}
|
|
use32bitcontext:=(not processhandler.is64Bit) and (ssctrl in GetKeyShiftState);
|
|
|
|
if use32bitcontext then
|
|
begin
|
|
//override, the user wants the 32-bit context
|
|
|
|
ZeroMemory(@c32, sizeof(c32));
|
|
c32.ContextFlags:=CONTEXT_ALL;
|
|
x:=WOW64GetThreadContext(th, c32);
|
|
if x then
|
|
begin
|
|
//convert
|
|
c.Dr0:=c32.Dr0;
|
|
c.Dr1:=c32.Dr1;
|
|
c.Dr2:=c32.Dr2;
|
|
c.Dr3:=c32.Dr3;
|
|
c.Dr6:=c32.Dr6;
|
|
c.Dr7:=c32.Dr7;
|
|
c.Rax:=c32.eax;
|
|
c.Rbx:=c32.ebx;
|
|
c.Rcx:=c32.ecx;
|
|
c.Rdx:=c32.edx;
|
|
c.Rsi:=c32.esi;
|
|
c.Rdi:=c32.edi;
|
|
c.Rbp:=c32.ebp;
|
|
c.Rsp:=c32.esp;
|
|
c.Rip:=c32.eip;
|
|
|
|
|
|
end;
|
|
end
|
|
else
|
|
{$endif}
|
|
begin
|
|
|
|
c.ContextFlags:=CONTEXT_ALL or CONTEXT_EXTENDED_REGISTERS;
|
|
x:=GetThreadContext(th, c);
|
|
end;
|
|
|
|
|
|
|
|
if x then
|
|
begin
|
|
case regnr of
|
|
0: regaddress:=@c.Dr0;
|
|
1: regaddress:=@c.Dr1;
|
|
2: regaddress:=@c.Dr2;
|
|
3: regaddress:=@c.Dr3;
|
|
4: regaddress:=@c.Dr6;
|
|
5: regaddress:=@c.Dr7;
|
|
|
|
6: regaddress:=@c.{$ifdef cpu64}rax{$else}eax{$endif};
|
|
7: regaddress:=@c.{$ifdef cpu64}rbx{$else}ebx{$endif};
|
|
8: regaddress:=@c.{$ifdef cpu64}rcx{$else}ecx{$endif};
|
|
9: regaddress:=@c.{$ifdef cpu64}rdx{$else}edx{$endif};
|
|
10: regaddress:=@c.{$ifdef cpu64}rsi{$else}esi{$endif};
|
|
11: regaddress:=@c.{$ifdef cpu64}rdi{$else}edi{$endif};
|
|
12: regaddress:=@c.{$ifdef cpu64}rbp{$else}ebp{$endif};
|
|
13: regaddress:=@c.{$ifdef cpu64}rsp{$else}esp{$endif};
|
|
14: regaddress:=@c.{$ifdef cpu64}rip{$else}eip{$endif};
|
|
|
|
{$ifdef cpu64}
|
|
15: regaddress:=@c.r8;
|
|
16: regaddress:=@c.r9;
|
|
17: regaddress:=@c.r10;
|
|
18: regaddress:=@c.r11;
|
|
19: regaddress:=@c.r12;
|
|
20: regaddress:=@c.r13;
|
|
21: regaddress:=@c.r14;
|
|
22: regaddress:=@c.r15;
|
|
{$endif}
|
|
else
|
|
regaddress:=@v; //in case of bugs
|
|
end;
|
|
|
|
if processhandler.is64Bit then
|
|
v:=regaddress^
|
|
else
|
|
v:=pdword(regaddress)^;
|
|
|
|
input:=inttohex(v,8);
|
|
InputQuery(rsTLChangeValue,rsTLWhatShouldTheNewValueOfThisRegisterBe, input);
|
|
|
|
v:=StrToQWordEx('$'+input);
|
|
|
|
if processhandler.is64Bit then
|
|
regaddress^:=v
|
|
else
|
|
pdword(regaddress)^:=v;
|
|
|
|
{$ifdef cpu64}
|
|
if use32bitcontext then
|
|
begin
|
|
c32.ContextFlags:=CONTEXT_ALL;
|
|
c32.Dr0:=c.Dr0;
|
|
c32.Dr1:=c.Dr1;
|
|
c32.Dr2:=c.Dr2;
|
|
c32.Dr3:=c.Dr3;
|
|
c32.Dr6:=c.Dr6;
|
|
c32.Dr7:=c.Dr7;
|
|
c32.eax:=c.Rax;
|
|
c32.ebx:=c.rbx;
|
|
c32.ecx:=c.rcx;
|
|
c32.edx:=c.rdx;
|
|
c32.esi:=c.rsi;
|
|
c32.edi:=c.rdi;
|
|
c32.ebp:=c.rbp;
|
|
c32.esp:=c.rsp;
|
|
c32.eip:=c.rip;
|
|
|
|
if WOW64SetThreadContext(th, c32)=false then
|
|
showmessage(rsTLFailedErrorcode+inttostr(GetLastError));
|
|
end
|
|
else
|
|
{$endif}
|
|
begin
|
|
c.ContextFlags:=CONTEXT_ALL or CONTEXT_EXTENDED_REGISTERS;
|
|
if SetThreadContext(th, c)=false then
|
|
showmessage(rsTLFailedErrorcode+inttostr(GetLastError));
|
|
end;
|
|
end;
|
|
|
|
resumethread(th);
|
|
closehandle(th);
|
|
|
|
|
|
|
|
threadTreeviewExpanding(threadTreeview, s,x);
|
|
|
|
|
|
threadTreeview.Items.SelectOnlyThis(threadTreeview.Items[ai]);
|
|
threadTreeview.Selected:=threadTreeview.Items[ai];
|
|
|
|
|
|
|
|
end;
|
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
//suspend the thread
|
|
//get the current register value
|
|
//show and edit
|
|
//convert back to integer
|
|
//resume thread
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
|
|
procedure TfrmThreadlist.threadTreeviewExpanding(Sender: TObject;
|
|
Node: TTreeNode; var AllowExpansion: Boolean);
|
|
function rw2str(x: byte): string;
|
|
begin
|
|
case x of
|
|
0: result:=rsTLExecute;
|
|
1: result:=rsTLWrite;
|
|
2: result:=rsTLIO;
|
|
3: result:=rsTLAccess;
|
|
end;
|
|
end;
|
|
|
|
function len2str(x: byte): string;
|
|
begin
|
|
case x of
|
|
0: result:=rsTL1Bytes;
|
|
1: result:=rsTL2Bytes;
|
|
2: result:=rsTL8Bytes;
|
|
3: result:=rsTL4Bytes;
|
|
end;
|
|
end;
|
|
|
|
var
|
|
c: TContext;
|
|
ca: TARMCONTEXT;
|
|
tid: dword;
|
|
th: thandle;
|
|
|
|
prefix: char;
|
|
s: string;
|
|
rw: byte;
|
|
len: byte;
|
|
|
|
drinfo: string;
|
|
|
|
ldtentry: TLDTEntry;
|
|
i: integer;
|
|
x: boolean;
|
|
|
|
{$ifdef cpu64}
|
|
use32bitcontext: boolean;
|
|
c32: TContext32;
|
|
{$endif}
|
|
|
|
cenet: TCEconnection;
|
|
begin
|
|
if node.level=0 then
|
|
begin
|
|
//extract thread info
|
|
if node.HasChildren then
|
|
Node.DeleteChildren;
|
|
|
|
tid:=strtoint('$'+Node.text);
|
|
|
|
cenet:=getConnection;
|
|
if cenet<>nil then
|
|
begin
|
|
if debuggerthread<>nil then
|
|
begin
|
|
if processhandler.SystemArchitecture=archArm then
|
|
begin
|
|
GetThreadContextArm(tid, ca);
|
|
with threadTreeview.items do
|
|
begin
|
|
AddChild(node,'R0='+inttohex(ca.R0,8));
|
|
AddChild(node,'R1='+inttohex(ca.R1,8));
|
|
AddChild(node,'R2='+inttohex(ca.R2,8));
|
|
AddChild(node,'R3='+inttohex(ca.R3,8));
|
|
AddChild(node,'R4='+inttohex(ca.R4,8));
|
|
AddChild(node,'R5='+inttohex(ca.R5,8));
|
|
AddChild(node,'R6='+inttohex(ca.R6,8));
|
|
AddChild(node,'R7='+inttohex(ca.R7,8));
|
|
AddChild(node,'R8='+inttohex(ca.R8,8));
|
|
AddChild(node,'R9='+inttohex(ca.R9,8));
|
|
AddChild(node,'R10='+inttohex(ca.R10,8));
|
|
AddChild(node,'FP='+inttohex(ca.FP,8));
|
|
AddChild(node,'IP='+inttohex(ca.IP,8));
|
|
AddChild(node,'SP='+inttohex(ca.SP,8));
|
|
AddChild(node,'LR='+inttohex(ca.LR,8));
|
|
AddChild(node,'PC='+inttohex(ca.PC,8));
|
|
AddChild(node,'CPSR='+inttohex(ca.CPSR,8));
|
|
AddChild(node,'ORIG_R0='+inttohex(ca.ORIG_R0,8));
|
|
|
|
end;
|
|
|
|
end
|
|
else
|
|
begin
|
|
GetThreadContext(tid, c);
|
|
|
|
if processhandler.is64Bit then
|
|
prefix:='r'
|
|
else
|
|
prefix:='e';
|
|
|
|
//no dr access yet for x86
|
|
with threadTreeview.items do
|
|
begin
|
|
AddChild(node,prefix+'ax='+inttohex(c.{$ifdef cpu64}rax{$else}eax{$endif},8));
|
|
AddChild(node,prefix+'bx='+inttohex(c.{$ifdef cpu64}rbx{$else}ebx{$endif},8));
|
|
AddChild(node,prefix+'cx='+inttohex(c.{$ifdef cpu64}rcx{$else}ecx{$endif},8));
|
|
AddChild(node,prefix+'dx='+inttohex(c.{$ifdef cpu64}rdx{$else}edx{$endif},8));
|
|
AddChild(node,prefix+'si='+inttohex(c.{$ifdef cpu64}rsi{$else}esi{$endif},8));
|
|
AddChild(node,prefix+'di='+inttohex(c.{$ifdef cpu64}rdi{$else}edi{$endif},8));
|
|
AddChild(node,prefix+'bp='+inttohex(c.{$ifdef cpu64}rbp{$else}ebp{$endif},8));
|
|
AddChild(node,prefix+'sp='+inttohex(c.{$ifdef cpu64}rsp{$else}esp{$endif},8));
|
|
AddChild(node,prefix+'ip='+inttohex(c.{$ifdef cpu64}rip{$else}eip{$endif},8));
|
|
|
|
{$ifdef cpu64}
|
|
if processhandler.is64bit then
|
|
begin
|
|
AddChild(node,'r8='+inttohex(c.r8,8));
|
|
AddChild(node,'r9='+inttohex(c.r9,8));
|
|
AddChild(node,'r10='+inttohex(c.r10,8));
|
|
AddChild(node,'r11='+inttohex(c.r11,8));
|
|
AddChild(node,'r12='+inttohex(c.r12,8));
|
|
AddChild(node,'r13='+inttohex(c.r13,8));
|
|
AddChild(node,'r14='+inttohex(c.r14,8));
|
|
AddChild(node,'r15='+inttohex(c.r15,8));
|
|
end;
|
|
{$endif}
|
|
|
|
threadTreeview.items.AddChild(node,'cs='+inttohex(c.SegCs,8));
|
|
{$ifdef cpu64}
|
|
//context has room for some extra data
|
|
AddChild(node,'fsbase='+inttohex(c.P2Home,8));
|
|
AddChild(node,'gsbase='+inttohex(c.P3Home,8));
|
|
{$endif}
|
|
|
|
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
end
|
|
else
|
|
begin
|
|
//threads can only be inspected when debugging (for now)
|
|
beep;
|
|
allowexpansion:=false;
|
|
exit;
|
|
end;
|
|
end
|
|
else
|
|
begin
|
|
|
|
th:=OpenThread(THREAD_QUERY_INFORMATION or THREAD_GET_CONTEXT, false, tid);
|
|
if th<>0 then
|
|
begin
|
|
zeromemory(@c,SizeOf(c));
|
|
c.ContextFlags:=CONTEXT_ALL or CONTEXT_EXTENDED_REGISTERS;
|
|
|
|
{$ifdef cpu64}
|
|
use32bitcontext:=(not processhandler.is64Bit) and (ssctrl in GetKeyShiftState);
|
|
|
|
if use32bitcontext then
|
|
begin
|
|
//override, the user wants the 32-bit context
|
|
|
|
ZeroMemory(@c32, sizeof(c32));
|
|
c32.ContextFlags:=CONTEXT_ALL;
|
|
x:=WOW64GetThreadContext(th, c32);
|
|
if x then
|
|
begin
|
|
//convert
|
|
c.Dr0:=c32.Dr0;
|
|
c.Dr1:=c32.Dr1;
|
|
c.Dr2:=c32.Dr2;
|
|
c.Dr3:=c32.Dr3;
|
|
c.Dr6:=c32.Dr6;
|
|
c.Dr7:=c32.Dr7;
|
|
c.Rax:=c32.eax;
|
|
c.Rbx:=c32.ebx;
|
|
c.Rcx:=c32.ecx;
|
|
c.Rdx:=c32.edx;
|
|
c.Rsi:=c32.esi;
|
|
c.Rdi:=c32.edi;
|
|
c.Rbp:=c32.ebp;
|
|
c.Rsp:=c32.esp;
|
|
c.Rip:=c32.eip;
|
|
c.SegCs:=c32.SegCs;
|
|
c.SegGs:=c32.seggs;
|
|
c.segfs:=c32.SegFs;
|
|
end;
|
|
end
|
|
else
|
|
{$endif}
|
|
x:=getThreadContext(th, c);
|
|
|
|
if x then
|
|
begin
|
|
threadTreeview.items.AddChild(node,'dr0='+inttohex(c.Dr0,{$ifdef cpu64}16{$else}8{$endif}));
|
|
threadTreeview.items.AddChild(node,'dr1='+inttohex(c.Dr1,{$ifdef cpu64}16{$else}8{$endif}));
|
|
threadTreeview.items.AddChild(node,'dr2='+inttohex(c.Dr2,{$ifdef cpu64}16{$else}8{$endif}));
|
|
threadTreeview.items.AddChild(node,'dr3='+inttohex(c.Dr3,{$ifdef cpu64}16{$else}8{$endif}));
|
|
threadTreeview.items.AddChild(node,'dr6='+inttohex(c.Dr6,{$ifdef cpu64}16{$else}8{$endif}));
|
|
|
|
s:='dr7='+inttohex(c.Dr7,{$ifdef cpu64}16{$else}8{$endif});
|
|
|
|
if c.dr7 and 1=1 then
|
|
begin
|
|
rw:=(c.dr7 shr 16) and 3;
|
|
len:=(c.dr7 shr 18) and 3;
|
|
|
|
drinfo:=drinfo+'1('+rw2str(rw)+' - '+len2str(len)+') ';
|
|
end;
|
|
|
|
if c.dr7 and 4=4 then
|
|
begin
|
|
rw:=(c.dr7 shr 16) and 3;
|
|
len:=(c.dr7 shr 18) and 3;
|
|
|
|
drinfo:=drinfo+'2('+rw2str(rw)+' - '+len2str(len)+') ';
|
|
end;
|
|
|
|
if c.dr7 and 16=16 then
|
|
begin
|
|
s:=s+'3(';
|
|
rw:=(c.dr7 shr 16) and 3;
|
|
len:=(c.dr7 shr 18) and 3;
|
|
|
|
drinfo:=drinfo+'3('+rw2str(rw)+' - '+len2str(len)+') ';
|
|
end;
|
|
|
|
if c.dr7 and 64=64 then
|
|
begin
|
|
|
|
rw:=(c.dr7 shr 16) and 3;
|
|
len:=(c.dr7 shr 18) and 3;
|
|
|
|
drinfo:=drinfo+'4('+rw2str(rw)+' - '+len2str(len)+') ';
|
|
end;
|
|
|
|
|
|
|
|
if drinfo<>'' then
|
|
s:=s+' :'+drinfo;
|
|
|
|
threadTreeview.items.AddChild(node,s);
|
|
|
|
if processhandler.is64Bit then
|
|
prefix:='r'
|
|
else
|
|
prefix:='e';
|
|
|
|
threadTreeview.items.AddChild(node,prefix+'ax='+inttohex(c.{$ifdef cpu64}rax{$else}eax{$endif},8));
|
|
threadTreeview.items.AddChild(node,prefix+'bx='+inttohex(c.{$ifdef cpu64}rbx{$else}ebx{$endif},8));
|
|
threadTreeview.items.AddChild(node,prefix+'cx='+inttohex(c.{$ifdef cpu64}rcx{$else}ecx{$endif},8));
|
|
threadTreeview.items.AddChild(node,prefix+'dx='+inttohex(c.{$ifdef cpu64}rdx{$else}edx{$endif},8));
|
|
threadTreeview.items.AddChild(node,prefix+'si='+inttohex(c.{$ifdef cpu64}rsi{$else}esi{$endif},8));
|
|
threadTreeview.items.AddChild(node,prefix+'di='+inttohex(c.{$ifdef cpu64}rdi{$else}edi{$endif},8));
|
|
threadTreeview.items.AddChild(node,prefix+'bp='+inttohex(c.{$ifdef cpu64}rbp{$else}ebp{$endif},8));
|
|
threadTreeview.items.AddChild(node,prefix+'sp='+inttohex(c.{$ifdef cpu64}rsp{$else}esp{$endif},8));
|
|
threadTreeview.items.AddChild(node,prefix+'ip='+inttohex(c.{$ifdef cpu64}rip{$else}eip{$endif},8));
|
|
|
|
{$ifdef cpu64}
|
|
if processhandler.is64bit then
|
|
begin
|
|
threadTreeview.items.AddChild(node,'r8='+inttohex(c.r8,8));
|
|
threadTreeview.items.AddChild(node,'r9='+inttohex(c.r9,8));
|
|
threadTreeview.items.AddChild(node,'r10='+inttohex(c.r10,8));
|
|
threadTreeview.items.AddChild(node,'r11='+inttohex(c.r11,8));
|
|
threadTreeview.items.AddChild(node,'r12='+inttohex(c.r12,8));
|
|
threadTreeview.items.AddChild(node,'r13='+inttohex(c.r13,8));
|
|
threadTreeview.items.AddChild(node,'r14='+inttohex(c.r14,8));
|
|
threadTreeview.items.AddChild(node,'r15='+inttohex(c.r15,8));
|
|
end;
|
|
{$endif}
|
|
|
|
threadTreeview.items.AddChild(node,'cs='+inttohex(c.SegCs,8));
|
|
|
|
|
|
if GetThreadSelectorEntry(th, c.segFs, ldtentry) then
|
|
threadTreeview.items.AddChild(node,'fsbase='+inttohex(ldtentry.BaseLow+ldtentry.HighWord.Bytes.BaseMid shl 16+ldtentry.HighWord.Bytes.BaseHi shl 24,8));
|
|
|
|
if GetThreadSelectorEntry(th, c.SegGs, ldtentry) then
|
|
threadTreeview.items.AddChild(node,'gsbase='+inttohex(ldtentry.BaseLow+ldtentry.HighWord.Bytes.BaseMid shl 16+ldtentry.HighWord.Bytes.BaseHi shl 24,8));
|
|
|
|
|
|
end
|
|
else threadTreeview.items.AddChild(node, rsCouldnTObtainContext);
|
|
closehandle(th);
|
|
end else
|
|
threadTreeview.items.AddChild(node, rsCouldnTOpenHandle);
|
|
|
|
end;
|
|
|
|
AllowExpansion:=true;
|
|
end
|
|
else
|
|
AllowExpansion:=false;
|
|
end;
|
|
|
|
initialization
|
|
{$i frmThreadlistunit.lrs}
|
|
|
|
end.
|