mirror of
https://github.com/cheat-engine/cheat-engine
synced 2026-08-15 02:26:08 -04:00
move the processlist function from cefuncproc to it's own unit start work on the jni library for java
224 lines
6.8 KiB
ObjectPascal
224 lines
6.8 KiB
ObjectPascal
unit frmstacktraceunit;
|
|
|
|
{$MODE Delphi}
|
|
|
|
interface
|
|
|
|
uses
|
|
windows, LCLIntf, Messages, SysUtils, Classes, Graphics, Controls, Forms,
|
|
Dialogs,NewKernelHandler, CEFuncProc, ComCtrls,imagehlp,CEDebugger, KernelDebugger,
|
|
Menus, LResources, debughelper, symbolhandler;
|
|
|
|
type
|
|
|
|
{ TfrmStacktrace }
|
|
|
|
TfrmStacktrace = class(TForm)
|
|
ListView1: TListView;
|
|
miManualStackwalk: TMenuItem;
|
|
PopupMenu1: TPopupMenu;
|
|
Refresh1: TMenuItem;
|
|
procedure FormCreate(Sender: TObject);
|
|
procedure FormClose(Sender: TObject; var Action: TCloseAction);
|
|
procedure ListView1DblClick(Sender: TObject);
|
|
procedure miManualStackwalkClick(Sender: TObject);
|
|
procedure Refresh1Click(Sender: TObject);
|
|
private
|
|
{ Private declarations }
|
|
procedure refreshtrace;
|
|
public
|
|
{ Public declarations }
|
|
procedure shadowstacktrace(context: _context; stackcopy: pointer; stackcopysize: integer);
|
|
procedure stacktrace(threadhandle:thandle;context:_context);
|
|
end;
|
|
|
|
var
|
|
frmStacktrace: TfrmStacktrace;
|
|
|
|
implementation
|
|
|
|
uses MemoryBrowserFormUnit, frmManualStacktraceConfigUnit, ProcessHandlerUnit;
|
|
|
|
var
|
|
useShadow: boolean;
|
|
shadowOrig: ptruint;
|
|
shadowNew: ptruint;
|
|
shadowSize: integer;
|
|
|
|
|
|
|
|
function rpm64(hProcess:THANDLE; qwBaseAddress:dword64; lpBuffer:pointer; nSize:dword; lpNumberOfBytesRead:lpdword):bool;stdcall; //should be lpptruint but the header file isn't correct
|
|
var pbr: PPtrUInt;
|
|
begin
|
|
pbr:=pptruint(lpNumberOfBytesRead);
|
|
result:=false;
|
|
{$ifndef cpu64}
|
|
if qwBaseAddress>$FFFFFFFF then exit;
|
|
{$endif}
|
|
|
|
if useShadow and InRangeQ(qwBaseAddress, shadowOrig, shadoworig+shadowSize) then
|
|
qwBaseAddress:=shadowNew+(qwBaseAddress-shadowOrig); //adjust the base address to the copy location
|
|
|
|
result:=newkernelhandler.readprocessmemory(hProcess, pointer(ptrUint(qwBaseAddress)), lpBuffer, nSize, pbr^);
|
|
end;
|
|
|
|
|
|
procedure TfrmStacktrace.stacktrace(threadhandle:thandle;context:_context);
|
|
var
|
|
stackframe: PStackframe64;
|
|
cxt:_context;
|
|
wow64ctx: CONTEXT32;
|
|
a,b,c,d: dword;
|
|
sa,sb,sc,sd:string;
|
|
machinetype: dword;
|
|
|
|
cp: pointer;
|
|
|
|
found: boolean;
|
|
begin
|
|
|
|
cxt:=context;
|
|
cp:=@cxt;
|
|
|
|
getmem(stackframe,sizeof(tstackframe));
|
|
zeromemory(stackframe,sizeof(tstackframe));
|
|
stackframe^.AddrPC.Offset:=context.{$ifdef cpu64}rip{$else}eip{$endif};
|
|
stackframe^.AddrPC.mode:=AddrModeFlat;
|
|
|
|
stackframe^.AddrStack.Offset:=context.{$ifdef cpu64}rsp{$else}esp{$endif};
|
|
stackframe^.AddrStack.Mode:=addrmodeflat;
|
|
|
|
stackframe^.AddrFrame.Offset:=context.{$ifdef cpu64}rbp{$else}ebp{$endif};
|
|
stackframe^.AddrFrame.Mode:=addrmodeflat;
|
|
|
|
listview1.items.clear;
|
|
|
|
|
|
//function StackWalk64(MachineType:dword; hProcess:THANDLE; hThread:THANDLE; StackFrame:LPSTACKFRAME64; ContextRecord:pointer; ReadMemoryRoutine:TREAD_PROCESS_MEMORY_ROUTINE64; FunctionTableAccessRoutine:TFUNCTION_TABLE_ACCESS_ROUTINE64; GetModuleBaseRoutine:TGET_MODULE_BASE_ROUTINE64; TranslateAddress:TTRANSLATE_ADDRESS_ROUTINE64):bool;stdcall;external External_library name 'StackWalk64';
|
|
{$ifdef cpu32}
|
|
machinetype:=IMAGE_FILE_MACHINE_I386;
|
|
{$else}
|
|
|
|
if processhandler.is64Bit then
|
|
machinetype:=IMAGE_FILE_MACHINE_AMD64
|
|
else
|
|
begin
|
|
// if (debuggerthread<>nil) and (debuggerthread.CurrentThread<>nil) then
|
|
|
|
ZeroMemory(@wow64ctx, sizeof (wow64ctx));
|
|
wow64ctx.Eip:=cxt.Rip; //shouldn't be needed though
|
|
wow64ctx.Ebp:=cxt.Rbp;
|
|
wow64ctx.Esp:=cxt.Rsp;
|
|
machinetype:=IMAGE_FILE_MACHINE_I386;
|
|
|
|
|
|
cp:=@wow64ctx;
|
|
|
|
end;
|
|
{$endif}
|
|
|
|
//because I provide a readprocessmemory the threadhandle just needs to be the unique for each thread. e.g threadid instead of threadhandle
|
|
while stackwalk64(machinetype,processhandle,threadhandle,stackframe,cp, rpm64 ,SymFunctionTableAccess64,SymGetModuleBase64,nil) do
|
|
begin
|
|
|
|
|
|
listview1.Items.Add.Caption:=symhandler.getNameFromAddress(stackframe^.AddrPC.Offset, true, true);
|
|
listview1.items[listview1.Items.Count-1].SubItems.add(inttohex(stackframe^.AddrStack.Offset,8));
|
|
listview1.items[listview1.Items.Count-1].SubItems.add(inttohex(stackframe^.AddrFrame.Offset,8));
|
|
listview1.items[listview1.Items.Count-1].SubItems.add(inttohex(stackframe^.AddrReturn.Offset,8));
|
|
|
|
a:=stackframe^.Params[0];
|
|
b:=stackframe^.Params[1];
|
|
c:=stackframe^.Params[2];
|
|
d:=stackframe^.Params[3];
|
|
|
|
sa:=symhandler.getNameFromAddress(a, found);
|
|
sb:=symhandler.getNameFromAddress(b, found);
|
|
sc:=symhandler.getNameFromAddress(c, found);
|
|
sd:=symhandler.getNameFromAddress(d, found);
|
|
|
|
listview1.items[listview1.Items.Count-1].SubItems.add(sa+','+sb+','+sc+','+sd+',...');
|
|
end;
|
|
|
|
end;
|
|
|
|
procedure TfrmstackTrace.refreshtrace;
|
|
{
|
|
Called when the debugger is paused on a breakpoint
|
|
}
|
|
var c: _CONTEXT;
|
|
begin
|
|
|
|
if (debuggerthread<>nil) and (debuggerthread.CurrentThread<>nil) then
|
|
stacktrace(debuggerthread.CurrentThread.handle,MemoryBrowser.lastdebugcontext);
|
|
end;
|
|
|
|
|
|
procedure TfrmStacktrace.FormCreate(Sender: TObject);
|
|
begin
|
|
refreshtrace;
|
|
end;
|
|
|
|
procedure TfrmStacktrace.FormClose(Sender: TObject;
|
|
var Action: TCloseAction);
|
|
begin
|
|
if frmstacktrace=self then //it can be something else as well
|
|
frmstacktrace:=nil;
|
|
|
|
action:=cafree;
|
|
end;
|
|
|
|
procedure TfrmStacktrace.ListView1DblClick(Sender: TObject);
|
|
begin
|
|
if listview1.Selected<>nil then
|
|
memorybrowser.disassemblerview.TopAddress:=symhandler.getAddressFromName(listview1.Selected.Caption);
|
|
end;
|
|
|
|
procedure TfrmStacktrace.shadowstacktrace(context: _context; stackcopy: pointer; stackcopysize: integer);
|
|
begin
|
|
useshadow:=true;
|
|
shadowOrig:=context.{$ifdef cpu64}rsp{$else}esp{$endif};
|
|
shadowNew:=ptruint(stackcopy);
|
|
shadowSize:=stackcopysize;
|
|
stacktrace(GetCurrentThread, context);
|
|
end;
|
|
|
|
|
|
procedure TfrmStacktrace.miManualStackwalkClick(Sender: TObject);
|
|
var c: _CONTEXT;
|
|
frmManualStacktraceConfig: TfrmManualStacktraceConfig;
|
|
begin
|
|
zeromemory(@c, sizeof(_CONTEXT));
|
|
|
|
frmManualStacktraceConfig:=tfrmManualStacktraceConfig.create(self);
|
|
if frmManualStacktraceConfig.showmodal=mrok then
|
|
begin
|
|
c.{$ifdef cpu64}Rip{$else}eip{$endif}:=frmManualStacktraceConfig.eip;
|
|
c.{$ifdef cpu64}Rbp{$else}ebp{$endif}:=frmManualStacktraceConfig.ebp;
|
|
c.{$ifdef cpu64}Rsp{$else}esp{$endif}:=frmManualStacktraceConfig.esp;
|
|
|
|
if frmManualStacktraceConfig.useshadow then
|
|
begin
|
|
useshadow:=true;
|
|
shadowOrig:=frmManualStacktraceConfig.shadoworig;
|
|
shadowNew:=frmManualStacktraceConfig.shadownew;
|
|
shadowSize:=frmManualStacktraceConfig.shadowsize;
|
|
end;
|
|
stacktrace(GetCurrentThreadId, c);
|
|
|
|
useShadow:=false;
|
|
end;
|
|
frmManualStacktraceConfig.free;
|
|
|
|
|
|
end;
|
|
|
|
procedure TfrmStacktrace.Refresh1Click(Sender: TObject);
|
|
begin
|
|
refreshtrace;
|
|
end;
|
|
|
|
initialization
|
|
{$i frmstacktraceunit.lrs}
|
|
|
|
end.
|