mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-06-28 23:18:20 +02:00
Debugger: added support for TThread.NameThreadForDebugging
This commit is contained in:
parent
1c008e121d
commit
2bc0a9b371
@ -218,6 +218,7 @@ type
|
|||||||
function ResetInstructionPointerAfterBreakpoint: boolean; virtual; abstract;
|
function ResetInstructionPointerAfterBreakpoint: boolean; virtual; abstract;
|
||||||
procedure DoBeforeBreakLocationMapChange; // A new location added / or a location removed => memory will change
|
procedure DoBeforeBreakLocationMapChange; // A new location added / or a location removed => memory will change
|
||||||
procedure ValidateRemovedBreakPointInfo;
|
procedure ValidateRemovedBreakPointInfo;
|
||||||
|
function GetName: String; virtual;
|
||||||
public
|
public
|
||||||
constructor Create(const AProcess: TDbgProcess; const AID: Integer; const AHandle: THandle); virtual;
|
constructor Create(const AProcess: TDbgProcess; const AID: Integer; const AHandle: THandle); virtual;
|
||||||
procedure DoBeforeProcessLoop;
|
procedure DoBeforeProcessLoop;
|
||||||
@ -266,6 +267,7 @@ type
|
|||||||
procedure StoreStepInfo(AnAddr: TDBGPtr = 0);
|
procedure StoreStepInfo(AnAddr: TDBGPtr = 0);
|
||||||
property ID: Integer read FID;
|
property ID: Integer read FID;
|
||||||
property Handle: THandle read FHandle;
|
property Handle: THandle read FHandle;
|
||||||
|
property Name: String read GetName;
|
||||||
property NextIsSingleStep: boolean read FNextIsSingleStep write FNextIsSingleStep;
|
property NextIsSingleStep: boolean read FNextIsSingleStep write FNextIsSingleStep;
|
||||||
property RegisterValueList: TDbgRegisterValueList read GetRegisterValueList;
|
property RegisterValueList: TDbgRegisterValueList read GetRegisterValueList;
|
||||||
property CallStackEntryList: TDbgCallstackEntryList read FCallStackEntryList;
|
property CallStackEntryList: TDbgCallstackEntryList read FCallStackEntryList;
|
||||||
@ -2916,6 +2918,11 @@ begin
|
|||||||
FPausedAtRemovedBreakPointState := rbUnknown;
|
FPausedAtRemovedBreakPointState := rbUnknown;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function TDbgThread.GetName: String;
|
||||||
|
begin
|
||||||
|
Result := 'Thread ' + IntToStr(FID);
|
||||||
|
end;
|
||||||
|
|
||||||
constructor TDbgThread.Create(const AProcess: TDbgProcess; const AID: Integer; const AHandle: THandle);
|
constructor TDbgThread.Create(const AProcess: TDbgProcess; const AID: Integer; const AHandle: THandle);
|
||||||
begin
|
begin
|
||||||
FID := AID;
|
FID := AID;
|
||||||
|
@ -277,6 +277,7 @@ type
|
|||||||
function GetDebugRegOffset(ind: byte): pointer;
|
function GetDebugRegOffset(ind: byte): pointer;
|
||||||
function ReadDebugReg(ind: byte; out AVal: PtrUInt): boolean;
|
function ReadDebugReg(ind: byte; out AVal: PtrUInt): boolean;
|
||||||
function WriteDebugReg(ind: byte; AVal: PtrUInt): boolean;
|
function WriteDebugReg(ind: byte; AVal: PtrUInt): boolean;
|
||||||
|
function GetName: String; override;
|
||||||
protected
|
protected
|
||||||
function ReadThreadState: boolean;
|
function ReadThreadState: boolean;
|
||||||
|
|
||||||
@ -539,6 +540,28 @@ begin
|
|||||||
result := true;
|
result := true;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function TDbgLinuxThread.GetName: String;
|
||||||
|
var
|
||||||
|
fh: THandle;
|
||||||
|
n: array[0..30] of AnsiChar;
|
||||||
|
c: LongInt;
|
||||||
|
begin
|
||||||
|
Result := '';
|
||||||
|
fh := FileOpen('/proc/' + IntToStr(Handle) + '/comm', fmOpenRead or fmShareDenyNone);
|
||||||
|
if fh <> THandle(-1) then begin
|
||||||
|
try
|
||||||
|
c := FileRead(fh, n, 30);
|
||||||
|
if c > 0 then begin
|
||||||
|
n[c] := #0;
|
||||||
|
Result := TrimRightSet(n, [' ', #10]);
|
||||||
|
end;
|
||||||
|
finally
|
||||||
|
FileClose(fh);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
if Result = '' then
|
||||||
|
Result := inherited GetName;
|
||||||
|
end;
|
||||||
|
|
||||||
function TDbgLinuxThread.ReadThreadState: boolean;
|
function TDbgLinuxThread.ReadThreadState: boolean;
|
||||||
var
|
var
|
||||||
|
@ -127,6 +127,7 @@ type
|
|||||||
TFpWinCtxFlags = (cfSkip, cfControl, cfFull);
|
TFpWinCtxFlags = (cfSkip, cfControl, cfFull);
|
||||||
TFpContextChangeFlag = (ccfControl, ccfInteger);
|
TFpContextChangeFlag = (ccfControl, ccfInteger);
|
||||||
TFpContextChangeFlags = set of TFpContextChangeFlag;
|
TFpContextChangeFlags = set of TFpContextChangeFlag;
|
||||||
|
PPWSTR = ^PWSTR;
|
||||||
|
|
||||||
{ TDbgWinThread }
|
{ TDbgWinThread }
|
||||||
|
|
||||||
@ -135,6 +136,8 @@ type
|
|||||||
FIsSuspended: Boolean;
|
FIsSuspended: Boolean;
|
||||||
FIsSkippingBreakPoint: Boolean;
|
FIsSkippingBreakPoint: Boolean;
|
||||||
FIsSkippingBreakPointAddress: TDBGPtr;
|
FIsSkippingBreakPointAddress: TDBGPtr;
|
||||||
|
FDoNotPollName: Boolean;
|
||||||
|
FName: String;
|
||||||
protected
|
protected
|
||||||
FThreadContextChanged: boolean;
|
FThreadContextChanged: boolean;
|
||||||
FThreadContextChangeFlags: TFpContextChangeFlags;
|
FThreadContextChangeFlags: TFpContextChangeFlags;
|
||||||
@ -144,6 +147,7 @@ type
|
|||||||
procedure LoadRegisterValues; override;
|
procedure LoadRegisterValues; override;
|
||||||
function GetFpThreadContext(var AStorage: TFpContext; out ACtxPtr: PFpContext; ACtxFlags: TFpWinCtxFlags): Boolean;
|
function GetFpThreadContext(var AStorage: TFpContext; out ACtxPtr: PFpContext; ACtxFlags: TFpWinCtxFlags): Boolean;
|
||||||
function SetFpThreadContext(ACtxPtr: PFpContext; ACtxFlags: TFpWinCtxFlags = cfSkip): Boolean;
|
function SetFpThreadContext(ACtxPtr: PFpContext; ACtxFlags: TFpWinCtxFlags = cfSkip): Boolean;
|
||||||
|
function GetName: String; override;
|
||||||
public
|
public
|
||||||
procedure Suspend;
|
procedure Suspend;
|
||||||
procedure SuspendForStepOverBreakPoint;
|
procedure SuspendForStepOverBreakPoint;
|
||||||
@ -313,6 +317,7 @@ var
|
|||||||
_Wow64GetThreadContext: function (hThread: THandle; var lpContext: WOW64_CONTEXT): BOOL; stdcall = nil;
|
_Wow64GetThreadContext: function (hThread: THandle; var lpContext: WOW64_CONTEXT): BOOL; stdcall = nil;
|
||||||
_Wow64SetThreadContext: function (hThread: THandle; const lpContext: WOW64_CONTEXT): BOOL; stdcall = nil;
|
_Wow64SetThreadContext: function (hThread: THandle; const lpContext: WOW64_CONTEXT): BOOL; stdcall = nil;
|
||||||
_DebugBreakProcess: function(Process:HANDLE): WINBOOL; stdcall = nil;
|
_DebugBreakProcess: function(Process:HANDLE): WINBOOL; stdcall = nil;
|
||||||
|
_GetThreadDescription: function(hThread: THandle; ppszThreadDescription: PPWSTR): HResult; stdcall = nil;
|
||||||
|
|
||||||
procedure LoadKernelEntryPoints;
|
procedure LoadKernelEntryPoints;
|
||||||
var
|
var
|
||||||
@ -330,6 +335,7 @@ begin
|
|||||||
Pointer(_DebugActiveProcess) := GetProcAddress(hMod, 'DebugActiveProcess');
|
Pointer(_DebugActiveProcess) := GetProcAddress(hMod, 'DebugActiveProcess');
|
||||||
Pointer(_GetFinalPathNameByHandle) := GetProcAddress(hMod, 'GetFinalPathNameByHandleW');
|
Pointer(_GetFinalPathNameByHandle) := GetProcAddress(hMod, 'GetFinalPathNameByHandleW');
|
||||||
Pointer(_DebugBreakProcess) := GetProcAddress(hMod, 'DebugBreakProcess');
|
Pointer(_DebugBreakProcess) := GetProcAddress(hMod, 'DebugBreakProcess');
|
||||||
|
Pointer(_GetThreadDescription) := GetProcAddress(hMod, 'GetThreadDescription');
|
||||||
{$ifdef cpux86_64}
|
{$ifdef cpux86_64}
|
||||||
Pointer(_IsWow64Process) := GetProcAddress(hMod, 'IsWow64Process');
|
Pointer(_IsWow64Process) := GetProcAddress(hMod, 'IsWow64Process');
|
||||||
Pointer(_Wow64GetThreadContext) := GetProcAddress(hMod, 'Wow64GetThreadContext');
|
Pointer(_Wow64GetThreadContext) := GetProcAddress(hMod, 'Wow64GetThreadContext');
|
||||||
@ -343,6 +349,7 @@ begin
|
|||||||
DebugLn(DBG_WARNINGS and (_DebugActiveProcess = nil), ['WARNING: Failed to get DebugActiveProcess']);
|
DebugLn(DBG_WARNINGS and (_DebugActiveProcess = nil), ['WARNING: Failed to get DebugActiveProcess']);
|
||||||
DebugLn(DBG_WARNINGS and (_GetFinalPathNameByHandle = nil), ['WARNING: Failed to get GetFinalPathNameByHandle']);
|
DebugLn(DBG_WARNINGS and (_GetFinalPathNameByHandle = nil), ['WARNING: Failed to get GetFinalPathNameByHandle']);
|
||||||
DebugLn(DBG_WARNINGS and (_DebugBreakProcess = nil), ['WARNING: Failed to get DebugBreakProcess']);
|
DebugLn(DBG_WARNINGS and (_DebugBreakProcess = nil), ['WARNING: Failed to get DebugBreakProcess']);
|
||||||
|
DebugLn(DBG_WARNINGS and (_GetThreadDescription = nil), ['WARNING: Failed to get GetThreadDescription']);
|
||||||
{$ifdef cpux86_64}
|
{$ifdef cpux86_64}
|
||||||
DebugLn(DBG_WARNINGS and (_IsWow64Process = nil), ['WARNING: Failed to get IsWow64Process']);
|
DebugLn(DBG_WARNINGS and (_IsWow64Process = nil), ['WARNING: Failed to get IsWow64Process']);
|
||||||
DebugLn(DBG_WARNINGS and (_Wow64GetThreadContext = nil), ['WARNING: Failed to get Wow64GetThreadContext']);
|
DebugLn(DBG_WARNINGS and (_Wow64GetThreadContext = nil), ['WARNING: Failed to get Wow64GetThreadContext']);
|
||||||
@ -1248,8 +1255,11 @@ function TDbgWinProcess.AnalyseDebugEvent(AThread: TDbgThread): TFPDEvent;
|
|||||||
OnDebugOutputEvent(Self, AEvent.dwProcessId, AEvent.dwThreadId, S);
|
OnDebugOutputEvent(Self, AEvent.dwProcessId, AEvent.dwThreadId, S);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
const
|
||||||
|
EXCEPTION_SET_THREADNAME = $406D1388;
|
||||||
var
|
var
|
||||||
InterceptAtFirst: Boolean;
|
InterceptAtFirst: Boolean;
|
||||||
|
threadname: String;
|
||||||
begin
|
begin
|
||||||
if AThread <> nil then
|
if AThread <> nil then
|
||||||
TDbgWinThread(AThread).EndSingleStepOverBreakPoint;
|
TDbgWinThread(AThread).EndSingleStepOverBreakPoint;
|
||||||
@ -1276,6 +1286,17 @@ begin
|
|||||||
end;
|
end;
|
||||||
EXCEPTION_SINGLE_STEP, STATUS_WX86_SINGLE_STEP: begin
|
EXCEPTION_SINGLE_STEP, STATUS_WX86_SINGLE_STEP: begin
|
||||||
result := deBreakpoint;
|
result := deBreakpoint;
|
||||||
|
end;
|
||||||
|
EXCEPTION_SET_THREADNAME: begin
|
||||||
|
if AThread <> nil then begin
|
||||||
|
if not ReadString(TDbgPtr(MDebugEvent.Exception.ExceptionRecord.ExceptionInformation[1]), 200, threadname) then
|
||||||
|
threadname := 'error getting threadname';
|
||||||
|
with TDbgWinThread(AThread) do begin
|
||||||
|
FName := threadname;
|
||||||
|
FDoNotPollName := True;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
result := deInternalContinue;
|
||||||
end
|
end
|
||||||
else begin
|
else begin
|
||||||
HandleException(MDebugEvent, InterceptAtFirst);
|
HandleException(MDebugEvent, InterceptAtFirst);
|
||||||
@ -1596,6 +1617,24 @@ begin
|
|||||||
DebugLn(DBG_WARNINGS and (not Result), ['Unable to set Context for ', ID, ': ', GetLastErrorText]);
|
DebugLn(DBG_WARNINGS and (not Result), ['Unable to set Context for ', ID, ': ', GetLastErrorText]);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function TDbgWinThread.GetName: String;
|
||||||
|
var
|
||||||
|
n: PWSTR;
|
||||||
|
begin
|
||||||
|
Result := '';
|
||||||
|
if FDoNotPollName then begin
|
||||||
|
Result := FName;
|
||||||
|
end else begin
|
||||||
|
if _GetThreadDescription <> nil then
|
||||||
|
if Succeeded(_GetThreadDescription(Handle, @n)) then begin
|
||||||
|
Result := WideCharToString(n);
|
||||||
|
LocalFree(HLOCAL(n));
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
if Result = '' then
|
||||||
|
Result := inherited GetName;
|
||||||
|
end;
|
||||||
|
|
||||||
procedure TDbgWinThread.Suspend;
|
procedure TDbgWinThread.Suspend;
|
||||||
var
|
var
|
||||||
r: DWORD;
|
r: DWORD;
|
||||||
|
@ -915,21 +915,21 @@ begin
|
|||||||
if Assigned(CallStack) and (CallStack.Count > 0) then begin
|
if Assigned(CallStack) and (CallStack.Count > 0) then begin
|
||||||
c := CallStack.Items[0];
|
c := CallStack.Items[0];
|
||||||
if t = nil then begin
|
if t = nil then begin
|
||||||
n := Threads.CurrentThreads.CreateEntry(c.AnAddress, nil, c.FunctionName, c.SourceFile, '', c.Line, FpThr.ID, 'Thread ' + IntToStr(FpThr.ID), 'paused');
|
n := Threads.CurrentThreads.CreateEntry(c.AnAddress, nil, c.FunctionName, c.SourceFile, '', c.Line, FpThr.ID, FpThr.Name, 'paused');
|
||||||
Threads.CurrentThreads.Add(n);
|
Threads.CurrentThreads.Add(n);
|
||||||
n.Free;
|
n.Free;
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
t.Init(c.AnAddress, nil, c.FunctionName, c.SourceFile, '', c.Line, FpThr.ID, 'Thread ' + IntToStr(FpThr.ID), 'paused');
|
t.Init(c.AnAddress, nil, c.FunctionName, c.SourceFile, '', c.Line, FpThr.ID, FpThr.Name, 'paused');
|
||||||
end
|
end
|
||||||
else begin
|
else begin
|
||||||
if t = nil then begin
|
if t = nil then begin
|
||||||
n := Threads.CurrentThreads.CreateEntry(0, nil, '', '', '', 0, FpThr.ID, 'Thread ' + IntToStr(FpThr.ID), 'paused');
|
n := Threads.CurrentThreads.CreateEntry(0, nil, '', '', '', 0, FpThr.ID, FpThr.Name, 'paused');
|
||||||
Threads.CurrentThreads.Add(n);
|
Threads.CurrentThreads.Add(n);
|
||||||
n.Free;
|
n.Free;
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
t.Init(0, nil, '', '', '', 0, FpThr.ID, 'Thread ' + IntToStr(FpThr.ID), 'paused');
|
t.Init(0, nil, '', '', '', 0, FpThr.ID, FpThr.Name, 'paused');
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user