FpDebug: Windows, replace global context (thread context/registers) with context per thread

git-svn-id: trunk@59569 -
This commit is contained in:
martin 2018-11-17 13:55:54 +00:00
parent 37e86f2e05
commit 3f70eb5a9d
2 changed files with 65 additions and 52 deletions

View File

@ -58,6 +58,11 @@ type
TDbgWinThread = class(TDbgThread)
protected
FThreadContextChanged: boolean;
FCurrentContext: PContext; // FCurrentContext := Pointer((PtrUInt(@_UnAligendContext) + 15) and not PtrUInt($F));
_UnAligendContext: record
C: TContext;
dummy: array[1..16] of byte;
end;
procedure LoadRegisterValues; override;
public
procedure SetSingleStep;
@ -687,19 +692,20 @@ function TDbgWinProcess.AnalyseDebugEvent(AThread: TDbgThread): TFPDEvent;
DebugLn('Thread ID: '+ IntToStr(MDebugEvent.dwThreadId));
if AThread = nil then Exit;
if TDbgWinThread(AThread).FCurrentContext = nil then Exit;
{$PUSH}{$R-}
{$ifdef cpui386}
with GCurrentContext^ do DebugLn(Format('DS: 0x%x, ES: 0x%x, FS: 0x%x, GS: 0x%x', [SegDs, SegEs, SegFs, SegGs]));
with GCurrentContext^ do DebugLn(Format('EAX: 0x%x, EBX: 0x%x, ECX: 0x%x, EDX: 0x%x, EDI: 0x%x, ESI: 0x%x', [Eax, Ebx, Ecx, Edx, Edi, Esi]));
with GCurrentContext^ do DebugLn(Format('CS: 0x%x, SS: 0x%x, EBP: 0x%x, EIP: 0x%x, ESP: 0x%x, EFlags: 0x%x [', [SegCs, SegSs, Ebp, Eip, Esp, EFlags]));
with TDbgWinThread(AThread).FCurrentContext^ do DebugLn(Format('DS: 0x%x, ES: 0x%x, FS: 0x%x, GS: 0x%x', [SegDs, SegEs, SegFs, SegGs]));
with TDbgWinThread(AThread).FCurrentContext^ do DebugLn(Format('EAX: 0x%x, EBX: 0x%x, ECX: 0x%x, EDX: 0x%x, EDI: 0x%x, ESI: 0x%x', [Eax, Ebx, Ecx, Edx, Edi, Esi]));
with TDbgWinThread(AThread).FCurrentContext^ do DebugLn(Format('CS: 0x%x, SS: 0x%x, EBP: 0x%x, EIP: 0x%x, ESP: 0x%x, EFlags: 0x%x [', [SegCs, SegSs, Ebp, Eip, Esp, EFlags]));
{$else}
with GCurrentContext^ do DebugLn(Format('SegDS: 0x%4.4x, SegES: 0x%4.4x, SegFS: 0x%4.4x, SegGS: 0x%4.4x', [SegDs, SegEs, SegFs, SegGs]));
with GCurrentContext^ do DebugLn(Format('RAX: 0x%16.16x, RBX: 0x%16.16x, RCX: 0x%16.16x, RDX: 0x%16.16x, RDI: 0x%16.16x, RSI: 0x%16.16x, R9: 0x%16.16x, R10: 0x%16.16x, R11: 0x%16.16x, R12: 0x%16.16x, R13: 0x%16.16x, R14: 0x%16.16x, R15: 0x%16.16x', [Rax, Rbx, Rcx, Rdx, Rdi, Rsi, R9, R10, R11, R12, R13, R14, R15]));
with GCurrentContext^ do DebugLn(Format('SegCS: 0x%4.4x, SegSS: 0x%4.4x, RBP: 0x%16.16x, RIP: 0x%16.16x, RSP: 0x%16.16x, EFlags: 0x%8.8x [', [SegCs, SegSs, Rbp, Rip, Rsp, EFlags]));
with TDbgWinThread(AThread).FCurrentContext^ do DebugLn(Format('SegDS: 0x%4.4x, SegES: 0x%4.4x, SegFS: 0x%4.4x, SegGS: 0x%4.4x', [SegDs, SegEs, SegFs, SegGs]));
with TDbgWinThread(AThread).FCurrentContext^ do DebugLn(Format('RAX: 0x%16.16x, RBX: 0x%16.16x, RCX: 0x%16.16x, RDX: 0x%16.16x, RDI: 0x%16.16x, RSI: 0x%16.16x, R9: 0x%16.16x, R10: 0x%16.16x, R11: 0x%16.16x, R12: 0x%16.16x, R13: 0x%16.16x, R14: 0x%16.16x, R15: 0x%16.16x', [Rax, Rbx, Rcx, Rdx, Rdi, Rsi, R9, R10, R11, R12, R13, R14, R15]));
with TDbgWinThread(AThread).FCurrentContext^ do DebugLn(Format('SegCS: 0x%4.4x, SegSS: 0x%4.4x, RBP: 0x%16.16x, RIP: 0x%16.16x, RSP: 0x%16.16x, EFlags: 0x%8.8x [', [SegCs, SegSs, Rbp, Rip, Rsp, EFlags]));
{$endif}
// luckely flag and debug registers are named the same
with GCurrentContext^ do
with TDbgWinThread(AThread).FCurrentContext^ do
begin
if EFlags and (1 shl 0) <> 0 then DebugLn('CF ');
if EFlags and (1 shl 2) <> 0 then DebugLn('PF ');
@ -783,8 +789,6 @@ begin
if HandleDebugEvent(MDebugEvent)
then result := deBreakpoint
else begin
FillChar(GCurrentContext^, SizeOf(GCurrentContext^), $EE);
if AThread <> nil
then begin
// TODO: move to TDbgThread
@ -1009,8 +1013,10 @@ end;
procedure TDbgWinThread.LoadRegisterValues;
begin
if FCurrentContext = nil then
ReadThreadState;
{$ifdef cpui386}
with GCurrentContext^ do
with FCurrentContext^ do
begin
FRegisterValueList.DbgRegisterAutoCreate['eax'].SetValue(Eax, IntToStr(Eax),4,0);
FRegisterValueList.DbgRegisterAutoCreate['ecx'].SetValue(Ecx, IntToStr(Ecx),4,1);
@ -1032,7 +1038,7 @@ begin
FRegisterValueList.DbgRegisterAutoCreate['gs'].SetValue(SegGs, IntToStr(SegGs),4,0);
end;
{$else}
with GCurrentContext^ do
with FCurrentContext^ do
begin
FRegisterValueList.DbgRegisterAutoCreate['rax'].SetValue(rax, IntToStr(rax),8,0);
FRegisterValueList.DbgRegisterAutoCreate['rbx'].SetValue(rbx, IntToStr(rbx),8,3);
@ -1068,17 +1074,19 @@ end;
procedure TDbgWinThread.SetSingleStep;
begin
GCurrentContext^.EFlags := GCurrentContext^.EFlags or FLAG_TRACE_BIT;
if FCurrentContext = nil then
ReadThreadState;
FCurrentContext^.EFlags := FCurrentContext^.EFlags or FLAG_TRACE_BIT;
FThreadContextChanged:=true;
end;
function TDbgWinThread.AddWatchpoint(AnAddr: TDBGPtr): integer;
function SetBreakpoint(var dr: {$ifdef cpui386}DWORD{$else}DWORD64{$endif}; ind: byte): boolean;
begin
if (Dr=0) and ((GCurrentContext^.Dr7 and (1 shl ind))=0) then
if (Dr=0) and ((FCurrentContext^.Dr7 and (1 shl ind))=0) then
begin
GCurrentContext^.Dr7 := GCurrentContext^.Dr7 or (1 shl (ind*2));
GCurrentContext^.Dr7 := GCurrentContext^.Dr7 or ($30000 shl (ind*4));
FCurrentContext^.Dr7 := FCurrentContext^.Dr7 or (1 shl (ind*2));
FCurrentContext^.Dr7 := FCurrentContext^.Dr7 or ($30000 shl (ind*4));
Dr:=AnAddr;
FThreadContextChanged:=true;
Result := True;
@ -1088,14 +1096,16 @@ function TDbgWinThread.AddWatchpoint(AnAddr: TDBGPtr): integer;
end;
begin
if FCurrentContext = nil then
ReadThreadState;
result := -1;
if SetBreakpoint(GCurrentContext^.Dr0, 0) then
if SetBreakpoint(FCurrentContext^.Dr0, 0) then
result := 0
else if SetBreakpoint(GCurrentContext^.Dr1, 1) then
else if SetBreakpoint(FCurrentContext^.Dr1, 1) then
result := 1
else if SetBreakpoint(GCurrentContext^.Dr2, 2) then
else if SetBreakpoint(FCurrentContext^.Dr2, 2) then
result := 2
else if SetBreakpoint(GCurrentContext^.Dr3, 3) then
else if SetBreakpoint(FCurrentContext^.Dr3, 3) then
result := 3
else
Process.Log('No hardware breakpoint available.');
@ -1105,10 +1115,10 @@ function TDbgWinThread.RemoveWatchpoint(AnId: integer): boolean;
function RemoveBreakpoint(var dr: {$ifdef cpui386}DWORD{$else}DWORD64{$endif}; ind: byte): boolean;
begin
if (Dr<>0) and ((GCurrentContext^.Dr7 and (1 shl (ind*2)))<>0) then
if (Dr<>0) and ((FCurrentContext^.Dr7 and (1 shl (ind*2)))<>0) then
begin
GCurrentContext^.Dr7 := GCurrentContext^.Dr7 xor (1 shl (ind*2));
GCurrentContext^.Dr7 := GCurrentContext^.Dr7 xor ($30000 shl (ind*4));
FCurrentContext^.Dr7 := FCurrentContext^.Dr7 xor (1 shl (ind*2));
FCurrentContext^.Dr7 := FCurrentContext^.Dr7 xor ($30000 shl (ind*4));
Dr:=0;
FThreadContextChanged:=true;
Result := True;
@ -1121,29 +1131,35 @@ function TDbgWinThread.RemoveWatchpoint(AnId: integer): boolean;
end;
begin
if FCurrentContext = nil then
ReadThreadState;
case AnId of
0: result := RemoveBreakpoint(GCurrentContext^.Dr0, 0);
1: result := RemoveBreakpoint(GCurrentContext^.Dr1, 1);
2: result := RemoveBreakpoint(GCurrentContext^.Dr2, 2);
3: result := RemoveBreakpoint(GCurrentContext^.Dr3, 3);
0: result := RemoveBreakpoint(FCurrentContext^.Dr0, 0);
1: result := RemoveBreakpoint(FCurrentContext^.Dr1, 1);
2: result := RemoveBreakpoint(FCurrentContext^.Dr2, 2);
3: result := RemoveBreakpoint(FCurrentContext^.Dr3, 3);
end
end;
procedure TDbgWinThread.BeforeContinue;
begin
if GCurrentContext^.Dr6 <> $ffff0ff0 then
if (FCurrentContext <> nil) and
(FCurrentContext^.Dr6 <> $ffff0ff0) then
begin
GCurrentContext^.Dr6:=$ffff0ff0;
FCurrentContext^.Dr6:=$ffff0ff0;
FThreadContextChanged:=true;
end;
if FThreadContextChanged then
begin
if SetThreadContext(Handle, GCurrentContext^) then
Assert(FCurrentContext <> nil, 'TDbgWinThread.BeforeContinue: none existing context was changed');
if SetThreadContext(Handle, FCurrentContext^) then
FThreadContextChanged:=false
else
Log('Thread %u: Unable to set context', [ID])
end;
FThreadContextChanged := False;
FCurrentContext := nil;
end;
function TDbgWinThread.ResetInstructionPointerAfterBreakpoint: boolean;
@ -1173,13 +1189,16 @@ begin
Exit;
end;
if FCurrentContext = nil then
ReadThreadState;
Context^.ContextFlags := CONTEXT_CONTROL;
{$ifdef cpui386}
Dec(Context^.Eip);
dec(GCurrentContext^.Eip);
dec(FCurrentContext^.Eip);
{$else}
Dec(Context^.Rip);
dec(GCurrentContext^.Rip);
dec(FCurrentContext^.Rip);
{$endif}
if not SetThreadContext(Handle, Context^)
@ -1193,36 +1212,43 @@ end;
function TDbgWinThread.ReadThreadState: boolean;
begin
GCurrentContext^.ContextFlags := CONTEXT_SEGMENTS or CONTEXT_INTEGER or CONTEXT_CONTROL or CONTEXT_DEBUG_REGISTERS;
FCurrentContext := Pointer((PtrUInt(@_UnAligendContext) + 15) and not PtrUInt($F));
FCurrentContext^.ContextFlags := CONTEXT_SEGMENTS or CONTEXT_INTEGER or CONTEXT_CONTROL or CONTEXT_DEBUG_REGISTERS;
SetLastError(0);
result := GetThreadContext(Handle, GCurrentContext^);
result := GetThreadContext(Handle, FCurrentContext^);
FRegisterValueListValid:=False;
end;
function TDbgWinThread.GetInstructionPointerRegisterValue: TDbgPtr;
begin
if FCurrentContext = nil then
ReadThreadState;
{$ifdef cpui386}
Result := GCurrentContext^.Eip;
Result := FCurrentContext^.Eip;
{$else}
Result := GCurrentContext^.Rip;
Result := FCurrentContext^.Rip;
{$endif}
end;
function TDbgWinThread.GetStackBasePointerRegisterValue: TDbgPtr;
begin
if FCurrentContext = nil then
ReadThreadState;
{$ifdef cpui386}
Result := GCurrentContext^.Ebp;
Result := FCurrentContext^.Ebp;
{$else}
Result := GCurrentContext^.Rbp;
Result := FCurrentContext^.Rbp;
{$endif}
end;
function TDbgWinThread.GetStackPointerRegisterValue: TDbgPtr;
begin
if FCurrentContext = nil then
ReadThreadState;
{$ifdef cpui386}
Result := GCurrentContext^.Esp;
Result := FCurrentContext^.Esp;
{$else}
Result := GCurrentContext^.Rsp;
Result := FCurrentContext^.Rsp;
{$endif}
end;

View File

@ -65,7 +65,6 @@ function GetLastErrorText: String; {$IFNDEF FPC} overload; {$ENDIF}
{$ifdef windows}
var
GCurrentContext: PContext;
MDebugEvent: TDebugEvent;
{$endif}
@ -121,17 +120,5 @@ begin
{$endif}
end;
{$ifdef windows}
var
_UnAligendContext: record
C: TContext;
dummy: array[1..16] of byte;
end;
initialization
GCurrentContext := Pointer((PtrUInt(@_UnAligendContext) + 15) and not PtrUInt($F));
{$endif}
end.