1742 lines
56 KiB
ObjectPascal
Executable File
1742 lines
56 KiB
ObjectPascal
Executable File
unit FoundCodeUnit;
|
|
|
|
{$MODE Delphi}
|
|
|
|
interface
|
|
|
|
uses
|
|
{$ifdef darwin}
|
|
macport, math,
|
|
{$endif}
|
|
{$ifdef windows}
|
|
windows,
|
|
{$endif}
|
|
LCLIntf, LResources, Messages, SysUtils, Variants, Classes, Graphics,
|
|
Controls, Forms, Dialogs, StdCtrls, disassembler, ExtCtrls, Menus,
|
|
NewKernelHandler, clipbrd, ComCtrls, fgl, formChangedAddresses, LastDisassembleData,
|
|
vmxfunctions, betterControls, Maps, syncobjs, contexthandler;
|
|
|
|
type
|
|
Tcoderecord = class
|
|
private
|
|
fhitcount: integer;
|
|
fcontext: pointer;
|
|
contexthandler: TContextInfo;
|
|
function getContext: pointer;
|
|
procedure setContext(ctx: Pointer);
|
|
|
|
procedure setHitcount(c: integer);
|
|
public
|
|
firstSeen: TDateTime;
|
|
lastSeen: TDateTime;
|
|
addressString: string;
|
|
address: ptrUint;
|
|
size: integer;
|
|
opcode: string;
|
|
description: string;
|
|
|
|
stack: record
|
|
savedsize: ptruint;
|
|
stack: pbyte;
|
|
end;
|
|
|
|
ipt: record
|
|
log: pointer;
|
|
size: integer;
|
|
end;
|
|
|
|
dbvmcontextbasic: PPageEventBasic;
|
|
|
|
|
|
diffcount: integer;
|
|
LastDisassembleData: TLastDisassembleData;
|
|
|
|
formChangedAddresses: TfrmChangedAddresses;
|
|
|
|
property hitcount: integer read fhitcount write setHitcount;
|
|
property context: pointer read getContext write setContext;
|
|
procedure savestack;
|
|
constructor create;
|
|
destructor destroy; override;
|
|
end;
|
|
|
|
type
|
|
|
|
{ TFoundCodeDialog }
|
|
TFoundCodeDialog=class;
|
|
|
|
{$ifdef windows}
|
|
TDBVMWatchPollThread=class(TThread)
|
|
private
|
|
results: PPageEventListDescriptor;
|
|
resultsize: integer;
|
|
|
|
cr3disassembler: Tcr3Disassembler;
|
|
procedure addEntriesToList;
|
|
public
|
|
id: integer;
|
|
fcd: TFoundCodeDialog;
|
|
procedure execute; override;
|
|
end;
|
|
{$endif}
|
|
|
|
|
|
TFoundCodeDialog = class(TForm)
|
|
FoundCodeList: TListView;
|
|
fcdImageList: TImageList;
|
|
dbvmMissedEntries: TLabel;
|
|
MenuItem1: TMenuItem;
|
|
MenuItem2: TMenuItem;
|
|
miFindWhatCodeAccesses: TMenuItem;
|
|
MenuItem4: TMenuItem;
|
|
miFindWhatAccesses: TMenuItem;
|
|
miSaveTofile: TMenuItem;
|
|
mInfo: TMemo;
|
|
Panel1: TPanel;
|
|
Description: TLabel;
|
|
Panel4: TPanel;
|
|
pmOptions: TPopupMenu;
|
|
ReplacewithcodethatdoesnothingNOP1: TMenuItem;
|
|
SaveDialog1: TSaveDialog;
|
|
Showthisaddressinthedisassembler1: TMenuItem;
|
|
Addtothecodelist1: TMenuItem;
|
|
MoreInfo1: TMenuItem;
|
|
Panel2: TPanel;
|
|
btnOK: TButton;
|
|
Panel3: TPanel;
|
|
btnExtraInfo: TButton;
|
|
btnAddToCodeList: TButton;
|
|
btnOpenDisassembler: TButton;
|
|
btnReplacewithnops: TButton;
|
|
N1: TMenuItem;
|
|
Copyselectiontoclipboard1: TMenuItem;
|
|
Splitter1: TSplitter;
|
|
timerEntryInfoUpdate: TTimer;
|
|
procedure FormCreate(Sender: TObject);
|
|
procedure FormDeactivate(Sender: TObject);
|
|
procedure FormDestroy(Sender: TObject);
|
|
procedure FormShow(Sender: TObject);
|
|
procedure FoundCodeListChange(Sender: TObject; Item: TListItem;
|
|
Change: TItemChange);
|
|
procedure FoundcodeListClick(Sender: TObject);
|
|
procedure btnOKClick(Sender: TObject);
|
|
procedure FormClose(Sender: TObject; var Action: TCloseAction);
|
|
procedure btnReplacewithnopsClick(Sender: TObject);
|
|
procedure btnOpenDisassemblerClick(Sender: TObject);
|
|
procedure btnAddToCodeListClick(Sender: TObject);
|
|
procedure FoundCodeListColumnClick(Sender: TObject; Column: TListColumn);
|
|
procedure FoundcodeListDblClick(Sender: TObject);
|
|
procedure btnExtraInfoClick(Sender: TObject);
|
|
procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
|
|
procedure FoundCodeListSelectItem(Sender: TObject; Item: TListItem;
|
|
Selected: Boolean);
|
|
procedure MenuItem1Click(Sender: TObject);
|
|
procedure miFindWhatAccessesClick(Sender: TObject);
|
|
procedure miFindWhatCodeAccessesClick(Sender: TObject);
|
|
procedure miSaveTofileClick(Sender: TObject);
|
|
procedure pmOptionsPopup(Sender: TObject);
|
|
procedure Copyselectiontoclipboard1Click(Sender: TObject);
|
|
procedure timerEntryInfoUpdateTimer(Sender: TObject);
|
|
private
|
|
{ Private declarations }
|
|
loadedPosition: boolean;
|
|
setcountwidth: boolean;
|
|
fdebuggerinterfacewatchid: integer;
|
|
{$ifdef windows}
|
|
dbvmwatchpollthread: TDBVMWatchPollThread;
|
|
{$endif}
|
|
|
|
usedmiFindWhatAccesses: boolean; //debug
|
|
|
|
countsortdirection: integer;
|
|
addresssortdirection: integer;
|
|
procedure stopdbvmwatch;
|
|
procedure addInfo(Coderecord: TCoderecord);
|
|
procedure moreinfo;
|
|
function getSelection: string;
|
|
procedure setdebuggerinterfacewatchid(id: integer);
|
|
procedure ChangedAddressClose(Sender: TObject; var CloseAction: TCloseAction);
|
|
public
|
|
{ Public declarations }
|
|
addresswatched: ptruint;
|
|
useexceptions: boolean;
|
|
usesdebugregs: boolean;
|
|
multiplerip: boolean;
|
|
|
|
dbvmwatch_unlock: qword;
|
|
|
|
|
|
addRecord_Address: ptruint;
|
|
iptlog: pointer; //do not free this. owned by the debugthreadhandler
|
|
iptlogsize: integer;
|
|
breakpoint: pointer;
|
|
|
|
seenAddressListCS: TCriticalSection; //should only be accessed by the debugger thread, but just in case...
|
|
seenAddressList: TMap; //list for the debugger thread to determine if it should be added to the list
|
|
|
|
procedure AddRecord;
|
|
procedure setChangedAddressCount(address :ptruint);
|
|
property debuggerinterfacewatchid: integer read fdebuggerinterfacewatchid write setdebuggerinterfacewatchid;
|
|
end;
|
|
|
|
|
|
resourcestring
|
|
strClose='Close';
|
|
rsFCThesWillSetASiftwareBreakpointInt3OnEverySingleOpcodeEtc = 'This will set a Software Breakpoint (int3) on every single opcode that will be reported here. Are you sure ?';
|
|
|
|
//var
|
|
// FoundCodeDialog: TFoundCodeDialog;
|
|
|
|
implementation
|
|
|
|
uses CEFuncProc, CEDebugger,debughelper, debugeventhandler, MemoryBrowserFormUnit,
|
|
MainUnit,kerneldebugger, AdvancedOptionsUnit ,formFoundcodeListExtraUnit,
|
|
MainUnit2, ProcessHandlerUnit, Globals, Parsers, DBK32functions, symbolhandler,
|
|
DebuggerInterfaceAPIWrapper, DBVMDebuggerInterface, breakpointtypedef;
|
|
|
|
|
|
|
|
{$IFDEF windows}
|
|
procedure TDBVMWatchPollThread.execute;
|
|
var
|
|
i: integer;
|
|
size: integer;
|
|
begin
|
|
cr3disassembler:=TCR3Disassembler.create;
|
|
getmem(results,4096);
|
|
resultsize:=4096;
|
|
zeromemory(results,resultsize);
|
|
|
|
try
|
|
while not terminated do
|
|
begin
|
|
size:=resultsize;
|
|
i:=dbvm_watch_retrievelog(id, results, size);
|
|
if i=0 then
|
|
begin
|
|
// OutputDebugString('TDBVMWatchPollThread returned 0');
|
|
// OutputDebugString('results^.numberOfEntries='+inttostr(results^.numberOfEntries));
|
|
// OutputDebugString('results^.maxSize='+inttostr(results^.maxSize));
|
|
|
|
//process data
|
|
if results^.numberOfEntries>0 then
|
|
begin
|
|
// OutputDebugString('calling addEntriesToList');
|
|
synchronize(addEntriesToList);
|
|
sleep(10);
|
|
end
|
|
else
|
|
sleep(50);
|
|
end
|
|
else
|
|
if i=2 then
|
|
begin
|
|
//not enough memory. Allocate twice the needed amount
|
|
// outputdebugstring(inttostr(resultsize)+' is too small for the buffer. It needs to be at least '+inttostr(size));
|
|
freememandnil(results);
|
|
|
|
|
|
resultsize:=size*2;
|
|
getmem(results, resultsize);
|
|
zeromemory(results,resultsize);
|
|
|
|
continue; //try again, no sleep
|
|
end else
|
|
begin
|
|
outputdebugstring('dbvm_watch_retrievelog returned '+inttostr(i)+' which is not supported');
|
|
exit;
|
|
end;
|
|
end;
|
|
|
|
|
|
except
|
|
on e: exception do
|
|
outputdebugstring('TDBVMWatchPollThread crash:'+e.Message);
|
|
end;
|
|
|
|
freememandnil(results);
|
|
freeandnil(cr3disassembler);
|
|
end;
|
|
{$ENDIF}
|
|
|
|
destructor TCodeRecord.Destroy;
|
|
begin
|
|
if stack.stack<>nil then
|
|
freememandnil(stack.stack);
|
|
|
|
if ipt.log<>nil then
|
|
freememandnil(ipt.log);
|
|
|
|
if fcontext<>nil then
|
|
freememandnil(fcontext);
|
|
|
|
inherited destroy;
|
|
end;
|
|
|
|
constructor TCodeRecord.create;
|
|
begin
|
|
formChangedAddresses:=nil;
|
|
firstseen:=now;
|
|
end;
|
|
|
|
|
|
{$IFDEF windows}
|
|
procedure TDBVMWatchPollThread.addEntriesToList;
|
|
var
|
|
coderecord: TCodeRecord;
|
|
c: pcontext;
|
|
i,j: integer;
|
|
opcode,desc: string;
|
|
li: TListItem;
|
|
ldi: TLastDisassembleData;
|
|
|
|
basicinfo: TPageEventBasic;
|
|
|
|
basic: PPageEventBasicArray;
|
|
extended: PPageEventExtendedArray absolute basic;
|
|
basics: PPageEventBasicWithStackArray absolute basic;
|
|
extendeds: PPageEventExtendedWithStackArray absolute basic;
|
|
|
|
address, address2: ptruint;
|
|
|
|
skip: boolean;
|
|
|
|
debug,debug2: pointer;
|
|
|
|
|
|
begin
|
|
outputdebugstring('addEntriesToList');
|
|
|
|
if results^.missedEntries>0 then
|
|
begin
|
|
fcd.dbvmMissedEntries.caption:=string.format(rsDBVMMissedEntries, [results^.missedEntries]);
|
|
if fcd.dbvmMissedEntries.visible=false then
|
|
fcd.dbvmMissedEntries.visible:=true;
|
|
end;
|
|
|
|
|
|
try
|
|
basic:=PPageEventBasicArray(ptruint(results)+sizeof(TPageEventListDescriptor));
|
|
|
|
for i:=0 to results^.numberOfEntries-1 do
|
|
begin
|
|
|
|
case results^.entryType of
|
|
0: basicinfo:=basic^[i];
|
|
1: basicinfo:=extended^[i].basic;
|
|
2: basicinfo:=basics^[i].basic;
|
|
3: basicinfo:=extendeds^[i].basic;
|
|
end;
|
|
address:=basicinfo.RIP;
|
|
outputdebugstring('testing entry '+inttostr(i)+'('+inttohex(address,8)+') - basicinfo.Count='+inttostr(basicinfo.Count+1));
|
|
|
|
//check if this address is inside the list
|
|
skip:=false;
|
|
for j:=0 to fcd.foundcodelist.Items.Count-1 do
|
|
begin
|
|
if TCodeRecord(fcd.foundcodelist.Items[j].data).address=address then
|
|
begin
|
|
//it's already in the list
|
|
if fcd.multiplerip=false then
|
|
begin
|
|
OutputDebugString(inttostr(j)+':Already in the list');
|
|
TCodeRecord(fcd.foundcodelist.Items[j].data).hitcount:=TCodeRecord(fcd.foundcodelist.Items[j].data).hitcount+(basicinfo.Count+1);
|
|
skip:=true;
|
|
|
|
fcd.foundcodelist.Items[j].caption:=inttostr(TCodeRecord(fcd.foundcodelist.Items[j].data).hitcount);
|
|
break;
|
|
end
|
|
else
|
|
begin
|
|
//check the other registers
|
|
if (basicinfo.RAX=TCodeRecord(fcd.foundcodelist.Items[j].data).dbvmcontextbasic^.RAX) and
|
|
(basicinfo.RBX=TCodeRecord(fcd.foundcodelist.Items[j].data).dbvmcontextbasic^.RBX) and
|
|
(basicinfo.RCX=TCodeRecord(fcd.foundcodelist.Items[j].data).dbvmcontextbasic^.RCX) and
|
|
(basicinfo.RDX=TCodeRecord(fcd.foundcodelist.Items[j].data).dbvmcontextbasic^.RDX) and
|
|
(basicinfo.RSP=TCodeRecord(fcd.foundcodelist.Items[j].data).dbvmcontextbasic^.RSP) and
|
|
(basicinfo.RBP=TCodeRecord(fcd.foundcodelist.Items[j].data).dbvmcontextbasic^.RBP) and
|
|
(basicinfo.RSI=TCodeRecord(fcd.foundcodelist.Items[j].data).dbvmcontextbasic^.RSI) and
|
|
(basicinfo.RDI=TCodeRecord(fcd.foundcodelist.Items[j].data).dbvmcontextbasic^.RDI) and
|
|
(basicinfo.R8=TCodeRecord(fcd.foundcodelist.Items[j].data).dbvmcontextbasic^.R8) and
|
|
(basicinfo.R9=TCodeRecord(fcd.foundcodelist.Items[j].data).dbvmcontextbasic^.R9) and
|
|
(basicinfo.R10=TCodeRecord(fcd.foundcodelist.Items[j].data).dbvmcontextbasic^.R10) and
|
|
(basicinfo.R11=TCodeRecord(fcd.foundcodelist.Items[j].data).dbvmcontextbasic^.R11) and
|
|
(basicinfo.R12=TCodeRecord(fcd.foundcodelist.Items[j].data).dbvmcontextbasic^.R12) and
|
|
(basicinfo.R13=TCodeRecord(fcd.foundcodelist.Items[j].data).dbvmcontextbasic^.R13) and
|
|
(basicinfo.R14=TCodeRecord(fcd.foundcodelist.Items[j].data).dbvmcontextbasic^.R14) and
|
|
(basicinfo.R15=TCodeRecord(fcd.foundcodelist.Items[j].data).dbvmcontextbasic^.R15) THEN
|
|
begin
|
|
TCodeRecord(fcd.foundcodelist.Items[j].data).hitcount:=TCodeRecord(fcd.foundcodelist.Items[j].data).hitcount+basicinfo.count;
|
|
|
|
skip:=true;
|
|
break;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
if skip then
|
|
begin
|
|
OutputDebugString('Skipping entry. it''s in the list');
|
|
continue;
|
|
end
|
|
else
|
|
OutputDebugString('Not in the list yet. Adding it');
|
|
|
|
coderecord:=TCoderecord.create;
|
|
getmem(coderecord.dbvmcontextbasic, sizeof(TPageEventBasicArray));
|
|
c:=coderecord.context;
|
|
|
|
coderecord.dbvmcontextbasic^:=basicinfo;
|
|
|
|
|
|
|
|
outputdebugstring('created coderecord and dbvmcontextbasic');
|
|
|
|
case results^.entryType of
|
|
|
|
0: ; //already done
|
|
|
|
1: //extended
|
|
begin
|
|
copymemory(@c^.{$ifdef cpu64}FltSave{$else}ext{$endif}, @extended^[i].fpudata, sizeof(c^.{$ifdef cpu64}FltSave{$else}ext{$endif}));
|
|
|
|
end;
|
|
|
|
2: //basic with stack
|
|
begin
|
|
coderecord.stack.savedsize:=4096;
|
|
getmem(coderecord.stack.stack, 4096);
|
|
|
|
copymemory(coderecord.stack.stack, @basics^[i].stack[0], 4096);
|
|
end;
|
|
|
|
3: //extended with stack
|
|
begin
|
|
copymemory(@c^.{$ifdef cpu64}FltSave{$else}ext{$endif}, @extendeds^[i].fpudata, sizeof(c^.{$ifdef cpu64}FltSave{$else}ext{$endif}));
|
|
coderecord.stack.savedsize:=4096;
|
|
getmem(coderecord.stack.stack, 4096);
|
|
|
|
copymemory(coderecord.stack.stack, @basics^[i].stack[0], 4096);
|
|
end;
|
|
|
|
else
|
|
begin
|
|
//error
|
|
outputdebugstring('unexpected type');
|
|
freememandnil(coderecord.dbvmcontextbasic);
|
|
freeandnil(coderecord);
|
|
exit;
|
|
end;
|
|
end;
|
|
|
|
address:=coderecord.dbvmcontextbasic^.RIP;
|
|
address2:=address;
|
|
|
|
cr3disassembler.cr3:=coderecord.dbvmcontextbasic^.CR3;
|
|
outputdebugstring(format('disassembling %.8x with CR3 %.8x: ',[address, cr3disassembler.cr3]));
|
|
|
|
opcode:=cr3disassembler.disassemble(address2,desc);
|
|
ldi:=cr3disassembler.LastDisassembleData;
|
|
|
|
outputdebugstring('opcode='+opcode);
|
|
|
|
|
|
coderecord.address:=address;
|
|
coderecord.size:=address2-address;
|
|
coderecord.opcode:=opcode;
|
|
coderecord.description:=desc;
|
|
coderecord.LastDisassembleData:=ldi;
|
|
coderecord.hitcount:=coderecord.dbvmcontextbasic^.Count;
|
|
|
|
//make compatible with older code:
|
|
OutputDebugString('setting up compatibility context');
|
|
|
|
c^.{$ifdef cpu64}Rax{$else}Eax{$endif}:=coderecord.dbvmcontextbasic^.RAX;
|
|
c^.{$ifdef cpu64}Rbx{$else}Ebx{$endif}:=coderecord.dbvmcontextbasic^.RBX;
|
|
c^.{$ifdef cpu64}Rcx{$else}Ecx{$endif}:=coderecord.dbvmcontextbasic^.RCX;
|
|
c^.{$ifdef cpu64}Rdx{$else}Edx{$endif}:=coderecord.dbvmcontextbasic^.RDX;
|
|
c^.{$ifdef cpu64}Rsi{$else}Esi{$endif}:=coderecord.dbvmcontextbasic^.RSI;
|
|
c^.{$ifdef cpu64}Rdi{$else}Edi{$endif}:=coderecord.dbvmcontextbasic^.RDI;
|
|
c^.{$ifdef cpu64}Rbp{$else}Ebp{$endif}:=coderecord.dbvmcontextbasic^.RBP;
|
|
c^.{$ifdef cpu64}Rsp{$else}Esp{$endif}:=coderecord.dbvmcontextbasic^.Rsp;
|
|
c^.{$ifdef cpu64}Rip{$else}Eip{$endif}:=coderecord.dbvmcontextbasic^.Rip;
|
|
{$ifdef cpu64}
|
|
c^.R8:=coderecord.dbvmcontextbasic^.R8;
|
|
c^.R9:=coderecord.dbvmcontextbasic^.R9;
|
|
c^.R10:=coderecord.dbvmcontextbasic^.R10;
|
|
c^.R11:=coderecord.dbvmcontextbasic^.R11;
|
|
c^.R12:=coderecord.dbvmcontextbasic^.R12;
|
|
c^.R13:=coderecord.dbvmcontextbasic^.R13;
|
|
c^.R14:=coderecord.dbvmcontextbasic^.R14;
|
|
c^.R15:=coderecord.dbvmcontextbasic^.R15;
|
|
{$endif}
|
|
c^.EFlags:=coderecord.dbvmcontextbasic^.FLAGS;
|
|
c^.SegCs:=coderecord.dbvmcontextbasic^.CS;
|
|
c^.SegSs:=coderecord.dbvmcontextbasic^.SS;
|
|
c^.SegDs:=coderecord.dbvmcontextbasic^.DS;
|
|
c^.SegEs:=coderecord.dbvmcontextbasic^.ES;
|
|
c^.SegFs:=coderecord.dbvmcontextbasic^.FS;
|
|
c^.SegGs:=coderecord.dbvmcontextbasic^.GS;
|
|
|
|
coderecord.hitcount:=coderecord.dbvmcontextbasic^.Count+1;
|
|
coderecord.diffcount:=0;
|
|
|
|
OutputDebugString('adding to the foundlist');
|
|
li:=fcd.FoundCodeList.Items.Add;
|
|
li.caption:='1';
|
|
li.SubItems.add(opcode);
|
|
li.data:=coderecord;
|
|
|
|
OutputDebugString('done with no errors');
|
|
end;
|
|
|
|
except
|
|
on e: exception do
|
|
outputdebugstring('TDBVMWatchPollThread.addEntriesToList error: '+e.message);
|
|
end;
|
|
end;
|
|
{$ENDIF}
|
|
|
|
procedure TCodeRecord.setHitcount(c: integer);
|
|
begin
|
|
fHitcount:=c;
|
|
lastSeen:=now;
|
|
end;
|
|
|
|
function TCodeRecord.getContext: pointer;
|
|
begin
|
|
if fcontext=nil then
|
|
begin
|
|
outputdebugstring('TCodeRecord.getContext: fContext was nil. Allocating it');
|
|
contexthandler:=getBestContextHandler;
|
|
fcontext:=getmem(contexthandler.ContextSize);
|
|
ZeroMemory(fcontext, contexthandler.ContextSize);
|
|
end;
|
|
|
|
result:=fcontext;
|
|
end;
|
|
|
|
procedure TCodeRecord.setContext(ctx: Pointer);
|
|
begin
|
|
contexthandler:=getBestContextHandler;
|
|
fcontext:=contexthandler.getCopy(ctx);
|
|
end;
|
|
|
|
procedure TCodeRecord.savestack;
|
|
var base: qword;
|
|
begin
|
|
getmem(stack.stack, savedStackSize);
|
|
base:=contexthandler.StackPointerRegister^.getValue(context);
|
|
|
|
if ReadProcessMemory(processhandle, pointer(base), stack.stack, savedStackSize, stack.savedsize)=false then
|
|
begin
|
|
//for some reason this sometimes returns 0 bytes read even if some of the bytes are readable.
|
|
stack.savedsize:=4096-(base mod 4096);
|
|
ReadProcessMemory(processhandle, pointer(base), stack.stack, stack.savedsize, stack.savedsize);
|
|
end;
|
|
end;
|
|
|
|
procedure TFoundCodeDialog.AddRecord;
|
|
{
|
|
Invoked by the debugger thread
|
|
It takes the data from the current thread and stores it in the processlist
|
|
}
|
|
var currentthread: TDebugThreadHandler;
|
|
opcode: string;
|
|
ldi: TLastDisassembleData;
|
|
address,address2: ptrUint;
|
|
desc: string;
|
|
|
|
coderecord: TCodeRecord;
|
|
i: integer;
|
|
|
|
li: tlistitem;
|
|
f: TfrmChangedAddresses;
|
|
|
|
d: TDisassembler;
|
|
begin
|
|
currentthread:=debuggerthread.CurrentThread;
|
|
address:=addRecord_Address;
|
|
|
|
//disassemble to get the opcode and size
|
|
address2:=address;
|
|
d:=TDisassembler.Create;
|
|
opcode:=d.disassemble(address2,desc);
|
|
ldi:=d.LastDisassembleData;
|
|
freeandnil(d);
|
|
|
|
|
|
coderecord:=TCoderecord.create;
|
|
coderecord.address:=address;
|
|
coderecord.size:=address2-address;
|
|
coderecord.opcode:=opcode;
|
|
coderecord.description:=desc;
|
|
coderecord.context:=currentthread.context; //this makes a copy, so no worries about pointers
|
|
coderecord.LastDisassembleData:=ldi;
|
|
coderecord.savestack;
|
|
coderecord.hitcount:=1;
|
|
coderecord.diffcount:=0;
|
|
|
|
if iptlogsize<>0 then
|
|
begin
|
|
getmem(coderecord.ipt.log, iptlogsize);
|
|
copymemory(coderecord.ipt.log, iptlog, iptlogsize);
|
|
end
|
|
else
|
|
coderecord.ipt.log:=nil;
|
|
|
|
coderecord.ipt.size:=iptlogsize;
|
|
|
|
|
|
seenAddressListCS.Enter;
|
|
try
|
|
seenAddressList.Add(address, coderecord);
|
|
except
|
|
//should NEVER happen as AddRecord is only called when it's not in the list, but just to be sure...
|
|
end;
|
|
seenAddressListCS.Leave;
|
|
|
|
li:=FoundCodeList.Items.Add;
|
|
li.caption:='1';
|
|
li.SubItems.add(opcode);
|
|
li.data:=coderecord;
|
|
|
|
if miFindWhatAccesses.Checked then //add it
|
|
coderecord.formChangedAddresses:=debuggerthread.FindWhatCodeAccesses(address, self); //ffffffuuuuuuuuuu. Rebuild again
|
|
|
|
debuggerthread.guiupdate:=true;
|
|
end;
|
|
|
|
procedure TFoundCodeDialog.stopdbvmwatch;
|
|
begin
|
|
{$IFDEF windows}
|
|
if dbvmwatchpollthread<>nil then
|
|
begin
|
|
dbvmwatchpollthread.Terminate;
|
|
dbvmwatchpollthread.WaitFor;
|
|
freeandnil(dbvmwatchpollthread);
|
|
end;
|
|
|
|
|
|
if debuggerinterfacewatchid<>-1 then
|
|
begin
|
|
dbvm_watch_delete(debuggerinterfacewatchid);
|
|
debuggerinterfacewatchid:=-1;
|
|
end;
|
|
|
|
if dbvmwatch_unlock<>0 then
|
|
begin
|
|
UnlockMemory(dbvmwatch_unlock);
|
|
dbvmwatch_unlock:=0;
|
|
end;
|
|
{$endif}
|
|
end;
|
|
|
|
procedure TFoundCodeDialog.setdebuggerinterfacewatchid(id: integer);
|
|
begin
|
|
{$IFDEF windows}
|
|
fdebuggerinterfacewatchid:=id;
|
|
|
|
if id<>-1 then
|
|
begin
|
|
if dbvmwatchpollthread<>nil then
|
|
freeandnil(dbvmwatchpollthread);
|
|
|
|
dbvmwatchpollthread:=TDBVMWatchPollThread.Create(true);
|
|
dbvmwatchpollthread.id:=id;
|
|
dbvmwatchpollthread.fcd:=self;
|
|
dbvmwatchpollthread.Start;
|
|
|
|
useexceptions:=true;
|
|
end;
|
|
{$ENDIF}
|
|
end;
|
|
|
|
|
|
procedure TFoundCodeDialog.setChangedAddressCount(address :ptruint);
|
|
var i: integer;
|
|
begin
|
|
for i:=0 to foundcodelist.Items.Count-1 do
|
|
if TCodeRecord(foundcodelist.Items[i].data).address=address then
|
|
begin
|
|
//increase the counter
|
|
inc(TCodeRecord(foundcodelist.Items[i].data).diffcount);
|
|
FoundcodeList.items[i].caption:=inttostr(TCodeRecord(foundcodelist.Items[i].data).hitcount)+' ('+inttostr(TCodeRecord(foundcodelist.Items[i].data).diffcount)+')';
|
|
exit;
|
|
end;
|
|
end;
|
|
|
|
procedure TFoundCodeDialog.addInfo(Coderecord: TCoderecord);
|
|
var
|
|
address: ptruint;
|
|
disassembled: array[1..5] of string;
|
|
firstchar: char;
|
|
hexcount: integer;
|
|
temp: string;
|
|
i: integer;
|
|
|
|
gplist: PContextElementRegisterList;
|
|
begin
|
|
if processhandler.is64Bit then
|
|
hexcount:=16
|
|
else
|
|
hexcount:=8;
|
|
|
|
address:=Coderecord.address;
|
|
address:=previousopcode(address);
|
|
address:=previousopcode(address);
|
|
|
|
disassembled[1]:=disassemble(address,temp);
|
|
disassembled[2]:=disassemble(address,temp);
|
|
|
|
if address<>coderecord.address then
|
|
begin
|
|
disassembled[1]:='';
|
|
disassembled[2]:='';
|
|
disassembled[3]:=coderecord.opcode;
|
|
disassembled[4]:='';
|
|
disassembled[5]:='';
|
|
end
|
|
else
|
|
begin
|
|
disassembled[3]:=disassemble(address,temp);
|
|
disassembled[4]:=disassemble(address,temp);
|
|
disassembled[5]:=disassemble(address,temp);
|
|
end;
|
|
|
|
minfo.Lines.BeginUpdate;
|
|
try
|
|
if coderecord.addressString<>'' then minfo.Lines.add(coderecord.addressString+':');
|
|
|
|
minfo.Lines.Add(disassembled[1]);
|
|
minfo.Lines.Add(disassembled[2]);
|
|
minfo.Lines.Add(disassembled[3]+' <<');
|
|
minfo.Lines.Add(disassembled[4]);
|
|
minfo.Lines.Add(disassembled[5]);
|
|
minfo.Lines.Add('');
|
|
|
|
|
|
gplist:=coderecord.contexthandler.getGeneralPurposeRegisters;
|
|
if gplist<>nil then
|
|
for i:=0 to length(gplist^)-1 do
|
|
minfo.Lines.Add(gplist^[i].name+'='+gplist^[i].getFullValueString(coderecord.context));
|
|
|
|
minfo.lines.add('');
|
|
minfo.lines.add('');
|
|
|
|
minfo.lines.add('First seen:'+TimeToStr(coderecord.firstSeen));
|
|
minfo.lines.add('Last seen:'+TimeToStr(coderecord.lastSeen));
|
|
|
|
|
|
|
|
finally
|
|
minfo.lines.EndUpdate;
|
|
end;
|
|
end;
|
|
|
|
procedure TFoundCodeDialog.ChangedAddressClose(Sender: TObject; var CloseAction: TCloseAction);
|
|
var i: integer;
|
|
coderecord: Tcoderecord;
|
|
begin
|
|
for i:=0 to FoundCodeList.Items.Count-1 do
|
|
begin
|
|
coderecord:=TCodeRecord(foundcodelist.items[i].data);
|
|
if coderecord.formChangedAddresses=sender then
|
|
coderecord.formChangedAddresses:=nil;
|
|
end;
|
|
|
|
end;
|
|
|
|
procedure TFoundCodeDialog.moreinfo;
|
|
var
|
|
disassembled: array[1..5] of record
|
|
s: string;
|
|
a: ptruint;
|
|
end;
|
|
|
|
address: ptrUint;
|
|
itemindex: integer;
|
|
temp,temp2: string;
|
|
maxregistervalue: ptrUint;
|
|
p: ptrUint;
|
|
i: integer;
|
|
coderecord: TCodeRecord;
|
|
firstchar: string;
|
|
|
|
|
|
|
|
w: integer;
|
|
|
|
FormFoundCodeListExtra: TFormFoundCodeListExtra;
|
|
|
|
ew: trect; //extra window rect
|
|
cw: trect; //changed address window rect
|
|
|
|
offset: integer;
|
|
|
|
lbl: TLabel;
|
|
|
|
d: TDisassembler;
|
|
|
|
gplist: PContextElementRegisterList;
|
|
begin
|
|
if processhandler.is64bit then
|
|
firstchar:='R' else firstchar:='E';
|
|
|
|
itemindex:=foundcodelist.ItemIndex;
|
|
if itemindex<>-1 then
|
|
begin
|
|
FormFoundCodeListExtra:=TFormFoundCodeListExtra.Create(application);
|
|
if useexceptions or (currentdebuggerinterface is TDBVMDebugInterface) then
|
|
FormFoundCodeListExtra.Label18.Visible:=false
|
|
else
|
|
FormFoundCodeListExtra.Label18.Visible:=true;
|
|
|
|
coderecord:=TCodeRecord(foundcodelist.items[itemindex].data);
|
|
if coderecord.formChangedAddresses<>nil then
|
|
begin
|
|
if not coderecord.formChangedAddresses.visible then //override userdefined positioning
|
|
begin
|
|
//LCLIntf.GetWindowRect(coderecord.formChangedAddresses.handle, cw);
|
|
//LCLIntf.GetWindowRect(FormFoundCodeListExtra.handle, ew);
|
|
|
|
//coderecord.formChangedAddresses.left:=(ew.Left-(cw.Right-cw.left));
|
|
//coderecord.formChangedAddresses.top:=FormFoundCodeListExtra.top;
|
|
|
|
end;
|
|
|
|
coderecord.formChangedAddresses.show;
|
|
coderecord.formChangedAddresses.AddHandlerClose(ChangedAddressClose);
|
|
end;
|
|
|
|
|
|
address:=coderecord.address;
|
|
{$IFDEF windows}
|
|
if CurrentDebuggerInterface is TDBVMDebugInterface then
|
|
begin
|
|
{$ifdef cpu64}
|
|
if pcontext(coderecord.context)^.P2Home<>0 then
|
|
begin
|
|
d:=TCR3Disassembler.Create;
|
|
TCR3Disassembler(d).CR3:=pcontext(coderecord.context)^.P2Home;
|
|
end
|
|
else
|
|
{$endif}
|
|
d:=TDisassembler.Create;
|
|
end
|
|
else
|
|
if coderecord.dbvmcontextbasic<>nil then
|
|
begin
|
|
d:=TCR3Disassembler.Create;
|
|
TCR3Disassembler(d).CR3:=coderecord.dbvmcontextbasic^.CR3;
|
|
end
|
|
else
|
|
{$ENDIF}
|
|
d:=TDisassembler.Create;
|
|
|
|
|
|
address:=previousopcode(address, d);
|
|
address:=previousopcode(address, d);
|
|
|
|
disassembled[1].a:=address;
|
|
disassembled[1].s:=d.disassemble(address,temp);
|
|
|
|
disassembled[2].a:=address;
|
|
disassembled[2].s:=d.disassemble(address,temp);
|
|
|
|
if address<>coderecord.address then
|
|
begin
|
|
disassembled[1].s:='';
|
|
disassembled[2].s:='';
|
|
disassembled[3].s:=coderecord.opcode;
|
|
disassembled[4].s:='';
|
|
disassembled[5].s:='';
|
|
end
|
|
else
|
|
begin
|
|
disassembled[3].a:=address;
|
|
disassembled[3].s:=d.disassemble(address,temp);
|
|
|
|
disassembled[4].a:=address;
|
|
disassembled[4].s:=d.disassemble(address,temp);
|
|
|
|
disassembled[5].a:=address;
|
|
disassembled[5].s:=d.disassemble(address,temp);
|
|
end;
|
|
|
|
freeandnil(d);
|
|
|
|
|
|
|
|
//convert disassembled strings to address+opcode only (no bytes)
|
|
//xxxxxxxx - xx xx xx - opcode
|
|
temp:=copy(disassembled[1].s,pos('-',disassembled[1].s)+2,length(disassembled[1].s));
|
|
temp:=copy(temp,pos('-',temp)+2,length(temp));
|
|
disassembled[1].s:=copy(disassembled[1].s,1,pos('-',disassembled[1].s))+' '+temp;
|
|
|
|
temp:=copy(disassembled[2].s,pos('-',disassembled[2].s)+2,length(disassembled[2].s));
|
|
temp:=copy(temp,pos('-',temp)+2,length(temp));
|
|
disassembled[2].s:=copy(disassembled[2].s,1,pos('-',disassembled[2].s))+' '+temp;
|
|
|
|
temp:=copy(disassembled[3].s,pos('-',disassembled[3].s)+2,length(disassembled[3].s));
|
|
temp:=copy(temp,pos('-',temp)+2,length(temp));
|
|
disassembled[3].s:=copy(disassembled[3].s,1,pos('-',disassembled[3].s))+' '+temp;
|
|
|
|
temp:=copy(disassembled[4].s,pos('-',disassembled[4].s)+2,length(disassembled[4].s));
|
|
temp:=copy(temp,pos('-',temp)+2,length(temp));
|
|
disassembled[4].s:=copy(disassembled[4].s,1,pos('-',disassembled[4].s))+' '+temp;
|
|
|
|
temp:=copy(disassembled[5].s,pos('-',disassembled[5].s)+2,length(disassembled[5].s));
|
|
temp:=copy(temp,pos('-',temp)+2,length(temp));
|
|
disassembled[5].s:=copy(disassembled[5].s,1,pos('-',disassembled[5].s))+' '+temp;
|
|
|
|
|
|
|
|
with FormFoundCodeListExtra do
|
|
begin
|
|
pnlEPTWatch.visible:=false;
|
|
|
|
label1.Caption:=disassembled[1].s;
|
|
label1.tag:=disassembled[1].a;
|
|
|
|
Label2.Caption:=disassembled[2].s;
|
|
Label2.tag:=disassembled[2].a;
|
|
|
|
Label3.Caption:=disassembled[3].s;
|
|
Label3.tag:=disassembled[3].a;
|
|
|
|
Label4.Caption:=disassembled[4].s;
|
|
Label4.tag:=disassembled[4].a;
|
|
|
|
Label5.Caption:=disassembled[5].s;
|
|
Label5.tag:=disassembled[5].a;
|
|
|
|
|
|
BeginFormUpdate;
|
|
while pnlRegisters.ControlCount>0 do
|
|
pnlRegisters.Controls[0].Destroy;
|
|
|
|
//controlsPerLine:
|
|
//9 - 8 digit registers = 3 controls/line (3 rows) (3x3) (24 digits/row)
|
|
//16 - 16 digit registers = registers = 5
|
|
|
|
gplist:=coderecord.contexthandler.getGeneralPurposeRegisters;
|
|
if gplist<>nil then
|
|
begin
|
|
pnlRegisters.ChildSizing.ControlsPerLine:=length(gplist^) div 3;
|
|
for i:=0 to length(gplist^)-1 do
|
|
begin
|
|
lbl:=tlabel.create(FormFoundCodeListExtra);
|
|
lbl.Caption:=gplist^[i].name+'='+gplist^[i].getValueString(coderecord.context);
|
|
lbl.tag:=ptruint(@gplist^[i]);
|
|
lbl.parent:=pnlRegisters;
|
|
lbl.OnMouseDown:=registerMouseDown;
|
|
lbl.OnDblClick:=RegisterDblClick;
|
|
end;
|
|
end;
|
|
EndFormUpdate;
|
|
(*
|
|
if processhandler.SystemArchitecture=archarm then
|
|
begin
|
|
formfoundcodelistextra.label17.caption:='';
|
|
|
|
if processhandler.is64Bit then
|
|
begin
|
|
//just start from scratch
|
|
while pnlRegisters.ControlCount>0 do
|
|
pnlRegisters.Controls[0].Destroy;
|
|
|
|
pnlRegisters.ChildSizing.ControlsPerLine:=6;
|
|
|
|
for i:=0 to 30 do
|
|
begin
|
|
lbl:=tlabel.create(FormFoundCodeListExtra);
|
|
lbl.Caption:=format('X%d=%.8x',[i,coderecord.arm64context.regs.X[i]]);
|
|
lbl.parent:=pnlRegisters;
|
|
lbl.OnMouseDown:=registerMouseDown;
|
|
lbl.OnDblClick:=RegisterDblClick;
|
|
end;
|
|
|
|
lbl:=tlabel.create(FormFoundCodeListExtra);
|
|
lbl.Caption:=format('SP=%.8x',[coderecord.arm64context.SP]);
|
|
lbl.parent:=pnlRegisters;
|
|
lbl.OnMouseDown:=registerMouseDown;
|
|
lbl.OnDblClick:=RegisterDblClick;
|
|
|
|
lbl:=tlabel.create(FormFoundCodeListExtra);
|
|
lbl.Caption:=format('PC=%.8x',[coderecord.arm64context.PC]);
|
|
lbl.parent:=pnlRegisters;
|
|
lbl.OnMouseDown:=registerMouseDown;
|
|
lbl.OnDblClick:=RegisterDblClick;
|
|
|
|
lbl:=tlabel.create(FormFoundCodeListExtra);
|
|
lbl.Caption:=format('PSTATE=%.8x',[coderecord.arm64context.PSTATE]);
|
|
lbl.parent:=pnlRegisters;
|
|
lbl.OnMouseDown:=registerMouseDown;
|
|
lbl.OnDblClick:=RegisterDblClick;
|
|
end
|
|
else
|
|
begin
|
|
//repurpose the x86 32-bit labels
|
|
lblRAX.caption:=' R0='+IntToHex(coderecord.armcontext.R0,8);
|
|
lblRDX.caption:=' R1='+IntToHex(coderecord.armcontext.R1,8);
|
|
lblRBP.caption:=' R2='+IntToHex(coderecord.armcontext.R2,8);
|
|
lblRBX.caption:=' R3='+IntToHex(coderecord.armcontext.R3,8);
|
|
lblRSI.caption:=' R4='+IntToHex(coderecord.armcontext.R4,8);
|
|
lblRSP.caption:=' R5='+IntToHex(coderecord.armcontext.R5,8);
|
|
lblRCX.caption:=' R6='+IntToHex(coderecord.armcontext.R6,8);
|
|
lblRDI.caption:=' R7='+IntToHex(coderecord.armcontext.R7,8);
|
|
lblRIP.caption:=' R8='+IntToHex(coderecord.armcontext.R8,8);
|
|
|
|
lblR9:=tlabel.Create(FormFoundCodeListExtra);
|
|
lblR9.caption:=' R9='+IntToHex(coderecord.armcontext.R9,8);
|
|
lblR9.parent:=pnlRegisters;
|
|
lblR9.OnMouseDown:=registerMouseDown;
|
|
lblR9.OnDblClick:=RegisterDblClick;
|
|
|
|
lblR10:=tlabel.Create(FormFoundCodeListExtra);
|
|
lblR10.caption:='R10='+IntToHex(coderecord.armcontext.R10,8);
|
|
lblR10.parent:=pnlRegisters;
|
|
lblR10.OnMouseDown:=registerMouseDown;
|
|
lblR10.OnDblClick:=RegisterDblClick;
|
|
|
|
lblR11:=tlabel.Create(FormFoundCodeListExtra);
|
|
lblR11.caption:=' FP='+IntToHex(coderecord.armcontext.FP,8);
|
|
lblR11.parent:=pnlRegisters;
|
|
lblR11.OnMouseDown:=registerMouseDown;
|
|
lblR11.OnDblClick:=RegisterDblClick;
|
|
//new row
|
|
lblR12:=tlabel.Create(FormFoundCodeListExtra);
|
|
lblR12.caption:=' IP='+IntToHex(coderecord.armcontext.IP,8);
|
|
lblR12.parent:=pnlRegisters;
|
|
lblR12.OnMouseDown:=registerMouseDown;
|
|
lblR12.OnDblClick:=RegisterDblClick;
|
|
|
|
lblR13:=tlabel.Create(FormFoundCodeListExtra);
|
|
lblR13.caption:=' SP='+IntToHex(coderecord.armcontext.SP,8);
|
|
lblR13.parent:=pnlRegisters;
|
|
lblR13.OnMouseDown:=registerMouseDown;
|
|
lblR13.OnDblClick:=RegisterDblClick;
|
|
|
|
lblR14:=tlabel.Create(FormFoundCodeListExtra);
|
|
lblR14.caption:=' LR='+IntToHex(coderecord.armcontext.LR,8);
|
|
lblR14.parent:=pnlRegisters;
|
|
lblR14.OnMouseDown:=registerMouseDown;
|
|
lblR14.OnDblClick:=RegisterDblClick;
|
|
//new line
|
|
|
|
lblR15:=tlabel.Create(FormFoundCodeListExtra);
|
|
lblR15.caption:=' PC='+IntToHex(coderecord.armcontext.PC,8);
|
|
lblR15.parent:=pnlRegisters;
|
|
lblR15.OnMouseDown:=registerMouseDown;
|
|
lblR15.OnDblClick:=RegisterDblClick;
|
|
|
|
lblR16:=tlabel.Create(FormFoundCodeListExtra);
|
|
lblR16.caption:=' CPSR='+IntToHex(coderecord.armcontext.CPSR,8);
|
|
lblR16.parent:=pnlRegisters;
|
|
lblR16.OnMouseDown:=registerMouseDown;
|
|
lblR16.OnDblClick:=RegisterDblClick;
|
|
|
|
lblR17:=tlabel.Create(FormFoundCodeListExtra);
|
|
lblR17.caption:=' ORIG_R0='+IntToHex(coderecord.armcontext.ORIG_R0,8);
|
|
lblR17.parent:=pnlRegisters;
|
|
lblR17.OnMouseDown:=registerMouseDown;
|
|
lblR17.OnDblClick:=RegisterDblClick;
|
|
end;
|
|
{Constraints.MinHeight:=panel6.top+(lblR17.top+lblR17.height)+16+panel5.height;
|
|
if height<Constraints.MinHeight then
|
|
height:=Constraints.MinHeight; }
|
|
end
|
|
else *)
|
|
begin
|
|
|
|
|
|
(*
|
|
|
|
lblRAX.caption:=firstchar+'AX='+IntToHex(coderecord.context.{$ifdef cpu64}Rax{$else}Eax{$endif},8);
|
|
lblRBX.caption:=firstchar+'BX='+IntToHex(coderecord.context.{$ifdef cpu64}Rbx{$else}Ebx{$endif},8);
|
|
lblRCX.caption:=firstchar+'CX='+IntToHex(coderecord.context.{$ifdef cpu64}Rcx{$else}Ecx{$endif},8);
|
|
lblRDX.caption:=firstchar+'DX='+IntToHex(coderecord.context.{$ifdef cpu64}Rdx{$else}Edx{$endif},8);
|
|
lblRSI.caption:=firstchar+'SI='+IntToHex(coderecord.context.{$ifdef cpu64}Rsi{$else}Esi{$endif},8);
|
|
lblRDI.caption:=firstchar+'DI='+IntToHex(coderecord.context.{$ifdef cpu64}Rdi{$else}Edi{$endif},8);
|
|
lblRSP.caption:=firstchar+'SP='+IntToHex(coderecord.context.{$ifdef cpu64}Rsp{$else}Esp{$endif},8);
|
|
lblRBP.caption:=firstchar+'BP='+IntToHex(coderecord.context.{$ifdef cpu64}Rbp{$else}Ebp{$endif},8);
|
|
lblRIP.caption:=firstchar+'IP='+IntToHex(coderecord.context.{$ifdef cpu64}Rip{$else}Eip{$endif},8);
|
|
|
|
{$ifdef cpu64}
|
|
if processhandler.is64bit then
|
|
begin
|
|
pnlRegisters.ChildSizing.ControlsPerLine:=5;
|
|
|
|
lblR8:=tlabel.Create(FormFoundCodeListExtra);
|
|
lblR8.caption:=' R8='+IntToHex(coderecord.context.r8,8);
|
|
lblR8.parent:=FormFoundCodeListExtra.pnlRegisters;
|
|
lblR8.OnMouseDown:=registerMouseDown;
|
|
lblR8.OnDblClick:=RegisterDblClick;
|
|
lblR8.Align:=lblrcx.Align;
|
|
lblR8.Color:=lblRAX.Color;
|
|
lblR8.Name:='lblR8';
|
|
|
|
|
|
|
|
lblR9:=tlabel.Create(FormFoundCodeListExtra);
|
|
lblR9.caption:=' R9='+IntToHex(coderecord.context.r9,8);
|
|
lblR9.parent:=FormFoundCodeListExtra.pnlRegisters;
|
|
lblR9.OnMouseDown:=registerMouseDown;
|
|
lblR9.OnDblClick:=RegisterDblClick;
|
|
lblR9.Align:=lblrcx.Align;
|
|
lblR9.Color:=lblRAX.Color;
|
|
|
|
|
|
lblR10:=tlabel.Create(FormFoundCodeListExtra);
|
|
lblR10.caption:='R10='+IntToHex(coderecord.context.r10,8);
|
|
lblR10.parent:=FormFoundCodeListExtra.pnlRegisters;
|
|
lblR10.OnMouseDown:=registerMouseDown;
|
|
lblR10.OnDblClick:=RegisterDblClick;
|
|
lblR10.Align:=lblrcx.Align;
|
|
lblR10.Color:=lblRAX.Color;
|
|
|
|
|
|
lblR11:=tlabel.Create(FormFoundCodeListExtra);
|
|
lblR11.caption:='R11='+IntToHex(coderecord.context.r11,8);
|
|
lblR11.parent:=FormFoundCodeListExtra.pnlRegisters;
|
|
lblR11.OnMouseDown:=registerMouseDown;
|
|
lblR11.OnDblClick:=RegisterDblClick;
|
|
lblR11.Align:=lblrcx.Align;
|
|
lblR11.Color:=lblRAX.Color;
|
|
|
|
|
|
lblR12:=tlabel.Create(FormFoundCodeListExtra);
|
|
lblR12.caption:='R12='+IntToHex(coderecord.context.r12,8);
|
|
lblR12.parent:=FormFoundCodeListExtra.pnlRegisters;
|
|
lblR12.OnMouseDown:=registerMouseDown;
|
|
lblR12.OnDblClick:=RegisterDblClick;
|
|
lblR12.Align:=lblrcx.Align;
|
|
lblR12.Color:=lblRAX.Color;
|
|
|
|
|
|
lblR13:=tlabel.Create(FormFoundCodeListExtra);
|
|
lblR13.caption:='R13='+IntToHex(coderecord.context.r13,8);
|
|
lblR13.parent:=FormFoundCodeListExtra.pnlRegisters;
|
|
lblR13.OnMouseDown:=registerMouseDown;
|
|
lblR13.OnDblClick:=RegisterDblClick;
|
|
lblR13.Align:=lblrcx.Align;
|
|
lblR13.Color:=lblRAX.Color;
|
|
|
|
|
|
lblR14:=tlabel.Create(FormFoundCodeListExtra);
|
|
lblR14.caption:='R14='+IntToHex(coderecord.context.r14,8);
|
|
lblR14.parent:=FormFoundCodeListExtra.pnlRegisters;
|
|
lblR14.OnMouseDown:=registerMouseDown;
|
|
lblR14.OnDblClick:=RegisterDblClick;
|
|
lblR14.Align:=lblrcx.Align;
|
|
lblR14.Color:=lblRAX.Color;
|
|
|
|
|
|
|
|
lblR15:=tlabel.Create(FormFoundCodeListExtra);
|
|
lblR15.caption:='R15='+IntToHex(coderecord.context.r15,8);
|
|
lblR15.parent:=FormFoundCodeListExtra.pnlRegisters;
|
|
lblR15.OnMouseDown:=registerMouseDown;
|
|
lblR15.OnDblClick:=RegisterDblClick;
|
|
lblR15.Align:=lblrcx.Align;
|
|
lblR15.Color:=lblRAX.Color;
|
|
|
|
if (currentdebuggerinterface is TDBVMDebugInterface) and (coderecord.context.P2Home<>0) then
|
|
begin
|
|
lblR16:=tlabel.Create(FormFoundCodeListExtra);
|
|
lblR16.caption:=' CR3='+IntToHex(coderecord.context.P2Home,8);
|
|
lblR16.parent:=FormFoundCodeListExtra.pnlRegisters;
|
|
lblR16.OnMouseDown:=registerMouseDown;
|
|
lblR16.OnDblClick:=RegisterDblClick;
|
|
lblR16.Align:=lblrcx.Align;
|
|
lblR16.Color:=lblRAX.Color;
|
|
end;
|
|
|
|
lblRBP.BringToFront;
|
|
lblRSP.BringToFront;
|
|
lblRIP.BringToFront;
|
|
end;
|
|
{$endif}
|
|
*)
|
|
|
|
if coderecord.dbvmcontextbasic<>nil then
|
|
begin
|
|
pnlEPTWatch.visible:=true;
|
|
lblPhysicalAddress.caption:=format('Physical Address=%.8x',[coderecord.dbvmcontextbasic^.PhysicalAddress]);
|
|
lblVirtualAddress.caption:=format('Virtual Address=%.8x',[coderecord.dbvmcontextbasic^.VirtualAddress]);
|
|
lblFSBase.caption:=format('FS Base=%.8x',[coderecord.dbvmcontextbasic^.FSBASE]);
|
|
lblGSBase.caption:=format('GS Base=%.8x',[coderecord.dbvmcontextbasic^.GSBASE]);
|
|
lblGSBaseKernel.caption:=format('GS Base Kernel=%.8x',[coderecord.dbvmcontextbasic^.GSBASE_KERNEL]);
|
|
lblCR3.caption:=format('CR3=%.8x',[coderecord.dbvmcontextbasic^.CR3]);
|
|
end
|
|
else
|
|
pnlEPTWatch.visible:=false;
|
|
end;
|
|
label6.Caption:=coderecord.description;
|
|
end;
|
|
|
|
//parse the disassembled[3] string to help the user find the pointer
|
|
//first find the [xxx]
|
|
|
|
temp:=lowercase(copy(disassembled[3].s,pos('[',disassembled[3].s)+1,(pos(']',disassembled[3].s)-1)-(pos('[',disassembled[3].s))));
|
|
firstchar:=lowercase(firstchar);
|
|
|
|
maxregistervalue:=0;
|
|
|
|
if temp<>'' then
|
|
begin
|
|
//parse
|
|
//find the biggest value, registers or exact value
|
|
|
|
if ((coderecord.LastDisassembleData.modrmValueType=dvtValue) and (coderecord.LastDisassembleData.hasSib=false)) then
|
|
begin
|
|
//only a value and no sib (the sib part can get messed up if it's a read)
|
|
|
|
offset:=integer(coderecord.LastDisassembleData.modrmValue);
|
|
|
|
if processhandler.SystemArchitecture=archX86 then
|
|
formfoundcodelistextra.probably:=addresswatched-offset;
|
|
end
|
|
else
|
|
begin
|
|
if processhandler.SystemArchitecture=archX86 then
|
|
begin
|
|
//todo: contexthandler lookups
|
|
//try the old code (coderecord.context is
|
|
if pos(firstchar+'ax',temp)>0 then maxregistervalue:=MaxX(maxregistervalue, pcontext(coderecord.context)^.{$ifdef cpu64}Rax{$else}Eax{$endif});
|
|
if pos(firstchar+'bx',temp)>0 then maxregistervalue:=MaxX(maxregistervalue, pcontext(coderecord.context)^.{$ifdef cpu64}Rbx{$else}Ebx{$endif});
|
|
if pos(firstchar+'cx',temp)>0 then maxregistervalue:=MaxX(maxregistervalue, pcontext(coderecord.context)^.{$ifdef cpu64}Rcx{$else}Ecx{$endif});
|
|
if pos(firstchar+'dx',temp)>0 then maxregistervalue:=MaxX(maxregistervalue, pcontext(coderecord.context)^.{$ifdef cpu64}Rdx{$else}Edx{$endif});
|
|
if pos(firstchar+'di',temp)>0 then maxregistervalue:=MaxX(maxregistervalue, pcontext(coderecord.context)^.{$ifdef cpu64}Rdi{$else}Edi{$endif});
|
|
if pos(firstchar+'si',temp)>0 then maxregistervalue:=MaxX(maxregistervalue, pcontext(coderecord.context)^.{$ifdef cpu64}Rsi{$else}Esi{$endif});
|
|
if pos(firstchar+'bp',temp)>0 then maxregistervalue:=MaxX(maxregistervalue, pcontext(coderecord.context)^.{$ifdef cpu64}Rbp{$else}Ebp{$endif});
|
|
if pos(firstchar+'sp',temp)>0 then maxregistervalue:=MaxX(maxregistervalue, pcontext(coderecord.context)^.{$ifdef cpu64}Rsp{$else}Esp{$endif});
|
|
{$ifdef cpu64}
|
|
if processhandler.is64Bit then
|
|
begin
|
|
if pos('r8',temp)>0 then maxregistervalue:=MaxX(maxregistervalue, pcontext(coderecord.context)^.r8);
|
|
if pos('r9',temp)>0 then maxregistervalue:=MaxX(maxregistervalue, pcontext(coderecord.context)^.r9);
|
|
if pos('r0',temp)>0 then maxregistervalue:=MaxX(maxregistervalue, pcontext(coderecord.context)^.r10);
|
|
if pos('r1',temp)>0 then maxregistervalue:=MaxX(maxregistervalue, pcontext(coderecord.context)^.r11);
|
|
if pos('r2',temp)>0 then maxregistervalue:=MaxX(maxregistervalue, pcontext(coderecord.context)^.r12);
|
|
if pos('r3',temp)>0 then maxregistervalue:=MaxX(maxregistervalue, pcontext(coderecord.context)^.r13);
|
|
if pos('r4',temp)>0 then maxregistervalue:=MaxX(maxregistervalue, pcontext(coderecord.context)^.r14);
|
|
if pos('r5',temp)>0 then maxregistervalue:=MaxX(maxregistervalue, pcontext(coderecord.context)^.r15);
|
|
end;
|
|
{$endif}
|
|
|
|
//the offset is always at the end, so read from back to front
|
|
//todo: use addresswatched
|
|
|
|
|
|
|
|
temp2:='';
|
|
for i:=length(temp) downto 1 do
|
|
if temp[i] in ['0'..'9','a'..'f'] then temp2:=temp[i]+temp2 else break;
|
|
|
|
if temp2<>'' then //I know this isn't completely correct e.g: [eax*4] but even then the 4 will NEVER be bigger than eax (unless it's to cause a crash)
|
|
begin
|
|
p:=StrToQWordEx('$'+temp2);
|
|
if p>maxregistervalue then maxregistervalue:=p;
|
|
end;
|
|
|
|
formfoundcodelistextra.probably:=maxregistervalue;
|
|
end; //todo: arm
|
|
end;
|
|
end else formfoundcodelistextra.label17.caption:='';
|
|
|
|
|
|
w:=formfoundcodelistextra.width;
|
|
w:=max(w,formfoundcodelistextra.label1.width);
|
|
w:=max(w,formfoundcodelistextra.label2.width);
|
|
w:=max(w,formfoundcodelistextra.label3.width);
|
|
w:=max(w,formfoundcodelistextra.label4.width);
|
|
w:=max(w,formfoundcodelistextra.label5.width);
|
|
|
|
if w<>formfoundcodelistextra.Width then
|
|
formfoundcodelistextra.Width:=w+5;
|
|
|
|
|
|
formfoundcodelistextra.context:=coderecord.contexthandler.getCopy(coderecord.context);
|
|
|
|
if coderecord.stack.stack<>nil then
|
|
begin
|
|
getmem(formfoundcodelistextra.stack.stack, coderecord.stack.savedsize);
|
|
formfoundcodelistextra.stack.savedsize:=coderecord.stack.savedsize;
|
|
CopyMemory(formfoundcodelistextra.stack.stack, coderecord.stack.stack, coderecord.stack.savedsize);
|
|
end;
|
|
|
|
if coderecord.ipt.log<>nil then
|
|
begin
|
|
getmem(formfoundcodelistextra.ipt.log, coderecord.ipt.size);
|
|
formfoundcodelistextra.ipt.size:=coderecord.ipt.size;
|
|
copymemory(FormFoundCodeListExtra.ipt.log, coderecord.ipt.log, coderecord.ipt.size);
|
|
end;
|
|
|
|
FormFoundCodeListExtra.Show;
|
|
end;
|
|
end;
|
|
|
|
procedure TFoundCodeDialog.FoundcodeListClick(Sender: TObject);
|
|
begin
|
|
end;
|
|
|
|
procedure TFoundCodeDialog.FormCreate(Sender: TObject);
|
|
var x: array of integer;
|
|
begin
|
|
btnOk.caption:=strStop;
|
|
|
|
setlength(x,0);
|
|
if loadformposition(self,x) then
|
|
loadedPosition:=true;
|
|
|
|
if length(x)>=1 then
|
|
begin
|
|
foundcodelist.Columns[0].Width:=x[0];
|
|
setcountwidth:=true;
|
|
end;
|
|
|
|
fdebuggerinterfacewatchid:=-1;
|
|
|
|
countsortdirection:=1;
|
|
addresssortdirection:=1;
|
|
|
|
seenAddressList:=tmap.Create(ituPtrSize,sizeof(pointer));
|
|
seenAddressListCS:=TCriticalSection.Create;
|
|
end;
|
|
|
|
procedure TFoundCodeDialog.FormDeactivate(Sender: TObject);
|
|
begin
|
|
|
|
end;
|
|
|
|
procedure TFoundCodeDialog.FormDestroy(Sender: TObject);
|
|
var i: integer;
|
|
cr: Tcoderecord;
|
|
s: string;
|
|
begin
|
|
stopDBVMWatch();
|
|
|
|
for i:=0 to FoundCodeList.Items.count-1 do
|
|
begin
|
|
cr:=Tcoderecord(FoundCodeList.Items[i].data);
|
|
|
|
if cr.formChangedAddresses<>nil then
|
|
begin
|
|
if usedmiFindWhatAccesses=false then
|
|
begin
|
|
MessageDlg('cr.formChangedAddresses is not nil but the function was never used. Fuck! cr.formChangedAddresses='+inttohex(ptruint(cr.formChangedAddresses),8), mtError,[mbok],0);
|
|
exit;
|
|
end;
|
|
cr.formChangedAddresses.Close;
|
|
end;
|
|
|
|
FoundCodeList.Items[i].data:=nil;
|
|
freeandnil(cr);
|
|
end;
|
|
|
|
|
|
|
|
FoundCodeList.Clear;
|
|
timerEntryInfoUpdate.Enabled:=false;
|
|
|
|
freeandnil(seenAddressList);
|
|
freeandnil(seenAddressListCS);
|
|
end;
|
|
|
|
procedure TFoundCodeDialog.FormShow(Sender: TObject);
|
|
begin
|
|
if not setcountwidth then
|
|
begin
|
|
FoundCodeList.Column[0].Width:=max(FoundCodeList.Column[0].Width, FoundCodeList.Canvas.TextWidth('9999'));
|
|
setcountwidth:=true;
|
|
end;
|
|
|
|
if not loadedPosition then
|
|
begin
|
|
width:=canvas.TextWidth('XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX');
|
|
height:=canvas.TextHeight('Q')*20;
|
|
FoundCodeList.Columns[0].Width:=canvas.TextWidth(' '+FoundCodeList.Columns[0].Caption+' ');
|
|
end;
|
|
end;
|
|
|
|
procedure TFoundCodeDialog.FoundCodeListChange(Sender: TObject;
|
|
Item: TListItem; Change: TItemChange);
|
|
begin
|
|
|
|
end;
|
|
|
|
procedure TFoundCodeDialog.btnOKClick(Sender: TObject);
|
|
var original: dword;
|
|
i: integer;
|
|
begin
|
|
if btnOK.caption=strStop then
|
|
begin
|
|
if debuggerthread<>nil then
|
|
debuggerthread.CodeFinderStop(self);
|
|
|
|
btnOK.caption:=strClose;
|
|
|
|
stopdbvmwatch;
|
|
end
|
|
else close;
|
|
|
|
|
|
end;
|
|
|
|
procedure TFoundCodeDialog.FormClose(Sender: TObject;
|
|
var Action: TCloseAction);
|
|
var
|
|
x: array of integer;
|
|
begin
|
|
if miFindWhatAccesses.Checked then
|
|
miFindWhatAccesses.Click; //unchecks it
|
|
|
|
|
|
if btnOK.caption=strStop then
|
|
if debuggerthread<>nil then
|
|
debuggerthread.CodeFinderStop(self);
|
|
|
|
|
|
|
|
if breakpoint<>nil then
|
|
begin
|
|
action:=caHide; //don't free. Only when the breakpoint is fully gone free it
|
|
dec(pbreakpoint(breakpoint)^.referencecount);
|
|
end
|
|
else
|
|
action:=caFree;
|
|
|
|
setlength(x,1);
|
|
x[0]:=FoundCodeList.Columns[0].Width;
|
|
saveformposition(self,x);
|
|
|
|
try
|
|
//rename so that the next created dialog can have this name
|
|
self.name:=self.name+'_tobedeleted'+inttohex(random(65535),4)+inttohex(random(65535),4)+inttohex(random(65535),4)+inttohex(random(65535),4)+'_'+inttohex(GetTickCount64,1);
|
|
except
|
|
end;
|
|
end;
|
|
|
|
procedure TFoundCodeDialog.btnReplacewithnopsClick(Sender: TObject);
|
|
var codelength: dword;
|
|
written: dword;
|
|
i,j: integer;
|
|
nops: array of byte;
|
|
a: dword;
|
|
original: dword;
|
|
|
|
mbi : _MEMORY_BASIC_INFORMATION;
|
|
|
|
coderecord: TCodeRecord;
|
|
begin
|
|
|
|
with foundcodelist do
|
|
begin
|
|
for j:=0 to foundcodelist.items.Count-1 do
|
|
begin
|
|
if foundcodelist.items[j].Selected then
|
|
begin
|
|
coderecord:=TcodeRecord(foundcodelist.items[j].data);
|
|
codelength:=coderecord.size;
|
|
//add it to the codelist
|
|
|
|
try
|
|
advancedoptions.AddToCodeList(coderecord.address,coderecord.size,false, foundcodelist.SelCount>1);
|
|
except
|
|
//already in the list, undo
|
|
end;
|
|
|
|
for i:=0 to AdvancedOptions.count-1 do
|
|
begin
|
|
advancedoptions.lvCodelist.ClearSelection;
|
|
if symhandler.getAddressFromName(AdvancedOptions.entries[i].code.symbolname,false)=coderecord.address then
|
|
begin
|
|
advancedoptions.lvCodelist.selected:=advancedoptions.lvCodelist.Items[i];
|
|
advancedoptions.lvCodelist.Items[i].Selected:=true;
|
|
if AdvancedOptions.entries[i].code.changed then
|
|
advancedoptions.miRestoreWithOriginalClick(advancedoptions.miRestoreWithOriginal)
|
|
else
|
|
advancedoptions.miReplaceWithNopsClick(advancedoptions.miReplaceWithNops);
|
|
end;
|
|
end;
|
|
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
|
|
end;
|
|
|
|
procedure TFoundCodeDialog.btnOpenDisassemblerClick(Sender: TObject);
|
|
var coderecord: TCodeRecord;
|
|
begin
|
|
if foundcodelist.itemindex<>-1 then
|
|
begin
|
|
coderecord:=TcodeRecord(foundcodelist.items[foundcodelist.itemindex].data);
|
|
memorybrowser.disassemblerview.SelectedAddress:=coderecord.address;
|
|
memorybrowser.panel1.visible:=true;
|
|
memorybrowser.show;
|
|
end;
|
|
end;
|
|
|
|
procedure TFoundCodeDialog.btnAddToCodeListClick(Sender: TObject);
|
|
var i: integer;
|
|
coderecord: TCodeRecord;
|
|
added: boolean=false;
|
|
begin
|
|
|
|
for i:=0 to foundcodelist.items.count-1 do
|
|
begin
|
|
if foundcodelist.items[i].Selected then
|
|
begin
|
|
coderecord:=TcodeRecord(foundcodelist.items[i].data);
|
|
if advancedoptions.AddToCodeList(coderecord.address,coderecord.size,false, foundcodelist.SelCount>1) then
|
|
added:=true;
|
|
end;
|
|
end;
|
|
|
|
if added then
|
|
advancedoptions.Show;
|
|
|
|
end;
|
|
|
|
function SortByAddress(Item1, Item2: TListItem; AOptionalParam: PtrInt): Integer stdcall;
|
|
begin
|
|
result:=AOptionalParam*(TcodeRecord(Item1.data).address-TcodeRecord(Item2.data).address);
|
|
|
|
end;
|
|
|
|
function SortByCount(Item1, Item2: TListItem; AOptionalParam: PtrInt): Integer stdcall;
|
|
begin
|
|
result:=AOptionalParam*(TcodeRecord(Item2.data).hitcount-TcodeRecord(Item1.data).hitcount);
|
|
end;
|
|
|
|
procedure TFoundCodeDialog.FoundCodeListColumnClick(Sender: TObject; Column: TListColumn);
|
|
begin
|
|
case column.index of
|
|
0:
|
|
begin
|
|
FoundcodeList.CustomSort(SortByCount,countsortdirection);
|
|
countsortdirection:=countsortdirection*-1;
|
|
end;
|
|
|
|
1:
|
|
begin
|
|
FoundcodeList.CustomSort(SortByAddress,addresssortdirection);
|
|
addresssortdirection:=addresssortdirection*-1;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TFoundCodeDialog.FoundcodeListDblClick(Sender: TObject);
|
|
begin
|
|
MoreInfo;
|
|
end;
|
|
|
|
procedure TFoundCodeDialog.btnExtraInfoClick(Sender: TObject);
|
|
begin
|
|
moreinfo;
|
|
end;
|
|
|
|
procedure TFoundCodeDialog.FormCloseQuery(Sender: TObject;
|
|
var CanClose: Boolean);
|
|
begin
|
|
if btnOK.caption=strStop then btnOK.Click;
|
|
CanClose:=true;
|
|
end;
|
|
|
|
|
|
procedure TFoundCodeDialog.FoundCodeListSelectItem(Sender: TObject;
|
|
Item: TListItem; Selected: Boolean);
|
|
var coderecord: TCodeRecord;
|
|
selectedRecord: integer;
|
|
i: integer;
|
|
begin
|
|
minfo.clear;
|
|
|
|
if foundcodelist.Selected<>nil then
|
|
begin
|
|
btnReplacewithnops.enabled:=true;
|
|
btnOpenDisassembler.enabled:=true;
|
|
btnAddToCodeList.enabled:=true;
|
|
btnExtraInfo.Enabled:=true;
|
|
|
|
coderecord:=TCodeRecord(foundcodelist.Selected.data);
|
|
description.Caption:=coderecord.description;
|
|
|
|
addinfo(coderecord);
|
|
|
|
{
|
|
for i:=0 to FoundCodeList.Items.Count-1 do
|
|
begin
|
|
if foundcodelist.items[i].Selected then
|
|
begin
|
|
coderecord:=TCodeRecord(foundcodelist.items[i].data);
|
|
addinfo(coderecord);
|
|
end;
|
|
end; }
|
|
|
|
//minfo.VertScrollBar.Position:=0;
|
|
minfo.SelStart:=0;
|
|
minfo.SelLength:=0;
|
|
end
|
|
else
|
|
begin
|
|
btnReplacewithnops.enabled:=false;
|
|
btnOpenDisassembler.enabled:=false;
|
|
btnAddToCodeList.enabled:=false;
|
|
btnExtraInfo.Enabled:=false;
|
|
if foundcodelist.Items.Count=0 then
|
|
description.caption:=rsUseTheGameApplicationForAWhile
|
|
else
|
|
description.caption:=rsSelectAnItemFromTheListForASmallDescription;
|
|
|
|
|
|
end;
|
|
end;
|
|
|
|
procedure TFoundCodeDialog.MenuItem1Click(Sender: TObject);
|
|
var i: integer;
|
|
begin
|
|
FoundCodeList.OnSelectItem:=nil;
|
|
for i:=0 to foundcodelist.items.count-1 do
|
|
FoundCodeList.Items[i].Selected:=true;
|
|
|
|
FoundCodeList.OnSelectItem:=FoundCodeListSelectItem;
|
|
end;
|
|
|
|
procedure TFoundCodeDialog.miFindWhatAccessesClick(Sender: TObject);
|
|
var i: integer;
|
|
coderecord: Tcoderecord;
|
|
f: TfrmChangedAddresses;
|
|
|
|
begin
|
|
usedmiFindWhatAccesses:=true;
|
|
|
|
if miFindWhatAccesses.checked then
|
|
begin
|
|
if MessageDlg(rsFCThesWillSetASiftwareBreakpointInt3OnEverySingleOpcodeEtc,mtWarning, [mbyes,mbno],0)=mryes then
|
|
begin
|
|
//go through all existing entries and set a FindWhatCodeAccesses bp
|
|
for i:=0 to FoundCodeList.Items.Count-1 do
|
|
begin
|
|
coderecord:=TCodeRecord(foundcodelist.items[i].data);
|
|
coderecord.diffcount:=0;
|
|
coderecord.formChangedAddresses:=debuggerthread.FindWhatCodeAccesses(coderecord.address, self);
|
|
end;
|
|
|
|
if FoundCodeList.Column[0].Width<FoundCodeList.Canvas.TextWidth('9999 (8)') then //make sure it's displayed
|
|
FoundCodeList.Column[0].Width:=FoundCodeList.Canvas.TextWidth('9999 (8)');
|
|
end
|
|
else
|
|
miFindWhatAccesses.checked:=false;
|
|
end
|
|
else
|
|
begin
|
|
//deactivate all bp's
|
|
//go through bplist and remove all bp's
|
|
for i:=0 to FoundCodeList.Items.Count-1 do
|
|
begin
|
|
coderecord:=TCodeRecord(foundcodelist.items[i].data);
|
|
if coderecord.formChangedAddresses<>nil then
|
|
begin
|
|
coderecord.formChangedAddresses.Close; //brings reference count to 0, so will autodestroy
|
|
coderecord.formChangedAddresses:=nil;
|
|
end;
|
|
end;
|
|
|
|
end;
|
|
end;
|
|
|
|
procedure TFoundCodeDialog.miFindWhatCodeAccessesClick(Sender: TObject);
|
|
var a: ptruint;
|
|
begin
|
|
if foundcodelist.ItemIndex<>-1 then
|
|
MemoryBrowser.findWhatthisCodeAccesses(TcodeRecord(foundcodelist.items[foundcodelist.itemindex].data).address);
|
|
end;
|
|
|
|
function TFoundCodeDialog.getSelection:string;
|
|
var
|
|
i: integer;
|
|
begin
|
|
result:='';
|
|
for i:=0 to FoundcodeList.Items.count-1 do
|
|
if FoundcodeList.items[i].selected then
|
|
result:=result+FoundcodeList.Items[i].subitems[0]+#13#10;
|
|
end;
|
|
|
|
procedure TFoundCodeDialog.miSaveTofileClick(Sender: TObject);
|
|
var
|
|
s: TStringList;
|
|
begin
|
|
if savedialog1.execute then
|
|
begin
|
|
s:=tstringlist.create;
|
|
s.text:=getSelection;
|
|
try
|
|
s.SaveToFile(savedialog1.filename);
|
|
finally
|
|
freeandnil(s);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TFoundCodeDialog.pmOptionsPopup(Sender: TObject);
|
|
begin
|
|
ReplacewithcodethatdoesnothingNOP1.Enabled:=foundcodelist.selcount>0;
|
|
Showthisaddressinthedisassembler1.enabled:=foundcodelist.itemindex<>-1;
|
|
Addtothecodelist1.enabled:=foundcodelist.selcount>0;
|
|
MoreInfo1.Enabled:=foundcodelist.itemindex<>-1;
|
|
miFindWhatCodeAccesses.enabled:=foundcodelist.itemindex<>-1;
|
|
|
|
Copyselectiontoclipboard1.enabled:=foundcodelist.selcount>0;
|
|
miSaveTofile.enabled:=Copyselectiontoclipboard1.Enabled;
|
|
end;
|
|
|
|
procedure TFoundCodeDialog.Copyselectiontoclipboard1Click(Sender: TObject);
|
|
begin
|
|
clipboard.AsText:=getSelection;
|
|
end;
|
|
|
|
procedure TFoundCodeDialog.timerEntryInfoUpdateTimer(Sender: TObject);
|
|
var
|
|
i: integer;
|
|
starttime: qword;
|
|
c: FoundCodeUnit.TCodeRecord;
|
|
updateAddressString: boolean;
|
|
|
|
news: string;
|
|
begin
|
|
starttime:=GetTickCount64;
|
|
updateAddressString:=true;
|
|
for i:=0 to foundcodelist.Items.Count-1 do
|
|
begin
|
|
c:=FoundCodeUnit.TCodeRecord(foundcodelist.items[i].data);
|
|
if c<>nil then
|
|
begin
|
|
if updateAddressString and (c.addressString='') then
|
|
c.addressString:=symhandler.getNameFromAddress(c.address);
|
|
|
|
if gettickcount64-starttime>250 then updateAddressString:=false; //next time better
|
|
|
|
if miFindWhatAccesses.checked or (TCodeRecord(foundcodelist.Items[i].data).diffcount<>0) then
|
|
news:=inttostr(c.hitcount)+' ('+inttostr(TCodeRecord(foundcodelist.Items[i].data).diffcount)+')'
|
|
else
|
|
news:=inttostr(c.hitcount);
|
|
|
|
if FoundcodeList.items[i].caption<>news then
|
|
FoundcodeList.items[i].caption:=news;
|
|
|
|
end;
|
|
end;
|
|
|
|
end;
|
|
|
|
initialization
|
|
{$i FoundCodeUnit.lrs}
|
|
|
|
end.
|