cheat-engine/Cheat Engine/frmstacktraceunit.pas
cheatengine@gmail.com 0f35a52416 move the processid and handle from cefuncproc to processhandlerunit
move the processlist function from cefuncproc to it's own unit
start work on the jni library for java
2014-09-08 12:00:14 +00:00

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.