From 35d829c9432f76bdaea7046343de6b8a37eb8dea Mon Sep 17 00:00:00 2001 From: martin Date: Tue, 18 Aug 2020 23:12:49 +0000 Subject: [PATCH] Debuggers (FpLLDB, FpGDBMI): add some safety checks. Do not free dwarf, in the middle of watch eval git-svn-id: trunk@63786 - --- .../lazdebuggerfpgdbmi/fpgdbmidebugger.pp | 86 +++++++++++++------ .../lazdebuggerfplldb/fplldbdebugger.pas | 27 ++++++ 2 files changed, 85 insertions(+), 28 deletions(-) diff --git a/components/lazdebuggers/lazdebuggerfpgdbmi/fpgdbmidebugger.pp b/components/lazdebuggers/lazdebuggerfpgdbmi/fpgdbmidebugger.pp index 315b423956..c936bf3544 100644 --- a/components/lazdebuggers/lazdebuggerfpgdbmi/fpgdbmidebugger.pp +++ b/components/lazdebuggers/lazdebuggerfpgdbmi/fpgdbmidebugger.pp @@ -76,6 +76,8 @@ type FMemManager: TFpDbgMemManager; // cache last context FLastContext: array [0..MAX_CTX_CACHE-1] of TFpDbgSymbolScope; + FLockUnLoadDwarf: integer; + FUnLoadDwarfNeeded: Boolean; protected function CreateCommandStartDebugging(AContinueCommand: TGDBMIDebuggerCommand): TGDBMIDebuggerCommandStartDebugging; override; function CreateLineInfo: TDBGLineInfo; override; @@ -85,6 +87,8 @@ type function HasDwarf: Boolean; procedure LoadDwarf; procedure UnLoadDwarf; + procedure LockUnLoadDwarf; + procedure UnLockUnLoadDwarf; function RequestCommand(const ACommand: TDBGCommand; const AParams: array of const; const ACallback: TMethod): Boolean; override; @@ -276,36 +280,41 @@ var m: TFpValue; n, v: String; begin - Ctx := FpDebugger.GetInfoContextForContext(ALocals.ThreadId, ALocals.StackFrame); - if (Ctx = nil) or (Ctx.SymbolAtAddress = nil) then begin - ALocals.SetDataValidity(ddsInvalid); - exit; - end; - - ProcVal := Ctx.ProcedureAtAddress; - - if (ProcVal = nil) then begin - ALocals.SetDataValidity(ddsInvalid); - exit; - end; - FpDebugger.FPrettyPrinter.AddressSize := ctx.SizeOfAddress; - FpDebugger.FPrettyPrinter.MemManager := ctx.MemManager; - - ALocals.Clear; - for i := 0 to ProcVal.MemberCount - 1 do begin - m := ProcVal.Member[i]; - if m <> nil then begin - if m.DbgSymbol <> nil then - n := m.DbgSymbol.Name - else - n := ''; - FpDebugger.FPrettyPrinter.PrintValue(v, m); - m.ReleaseReference; - ALocals.Add(n, v); + FpDebugger.LockUnLoadDwarf; + try + Ctx := FpDebugger.GetInfoContextForContext(ALocals.ThreadId, ALocals.StackFrame); + if (Ctx = nil) or (Ctx.SymbolAtAddress = nil) then begin + ALocals.SetDataValidity(ddsInvalid); + exit; end; + + ProcVal := Ctx.ProcedureAtAddress; + + if (ProcVal = nil) then begin + ALocals.SetDataValidity(ddsInvalid); + exit; + end; + FpDebugger.FPrettyPrinter.AddressSize := ctx.SizeOfAddress; + FpDebugger.FPrettyPrinter.MemManager := ctx.MemManager; + + ALocals.Clear; + for i := 0 to ProcVal.MemberCount - 1 do begin + m := ProcVal.Member[i]; + if m <> nil then begin + if m.DbgSymbol <> nil then + n := m.DbgSymbol.Name + else + n := ''; + FpDebugger.FPrettyPrinter.PrintValue(v, m); + m.ReleaseReference; + ALocals.Add(n, v); + end; + end; + ProcVal.ReleaseReference; + ALocals.SetDataValidity(ddsValid); + finally + FpDebugger.UnLockUnLoadDwarf; end; - ProcVal.ReleaseReference; - ALocals.SetDataValidity(ddsValid); end; function TFPGDBMILocals.FpDebugger: TFpGDBMIDebugger; @@ -569,6 +578,7 @@ begin if FWatchEvalLock > 0 then exit; inc(FWatchEvalLock); + FpDebugger.LockUnLoadDwarf; try // TODO: if the stack/thread is changed, registers will be wrong while (FpDebugger.FWatchEvalList.Count > 0) and (FEvaluationCmdObj = nil) do begin try @@ -598,6 +608,7 @@ begin end; finally dec(FWatchEvalLock); + FpDebugger.UnLockUnLoadDwarf; end; end; @@ -777,6 +788,11 @@ end; procedure TFpGDBMIDebugger.UnLoadDwarf; begin + if FLockUnLoadDwarf > 0 then begin + FUnLoadDwarfNeeded := True; + exit; + end; + FUnLoadDwarfNeeded := False; debugln(DBG_VERBOSE, ['TFpGDBMIDebugger.UnLoadDwarf ']); FreeAndNil(FDwarfInfo); FreeAndNil(FImageLoaderList); @@ -787,6 +803,18 @@ begin FreeAndNil(FPrettyPrinter); end; +procedure TFpGDBMIDebugger.LockUnLoadDwarf; +begin + inc(FLockUnLoadDwarf); +end; + +procedure TFpGDBMIDebugger.UnLockUnLoadDwarf; +begin + dec(FLockUnLoadDwarf); + if (FLockUnLoadDwarf <= 0) and FUnLoadDwarfNeeded then + UnLoadDwarf; +end; + function TFpGDBMIDebugger.RequestCommand(const ACommand: TDBGCommand; const AParams: array of const; const ACallback: TMethod): Boolean; var @@ -1030,6 +1058,7 @@ begin FPrettyPrinter.AddressSize := ctx.SizeOfAddress; FPrettyPrinter.MemManager := ctx.MemManager; + LockUnLoadDwarf; PasExpr := TFpPascalExpression.Create(AExpression, Ctx); try if not IsWatchValueAlive then exit; @@ -1130,6 +1159,7 @@ DebugLn(DBG_VERBOSE, [ErrorHandler.ErrorAsString(PasExpr.Error)]); finally PasExpr.Free; FMemManager.DefaultContext := nil; + UnLockUnLoadDwarf; end; end; diff --git a/components/lazdebuggers/lazdebuggerfplldb/fplldbdebugger.pas b/components/lazdebuggers/lazdebuggerfplldb/fplldbdebugger.pas index c36065e81d..c51951a757 100644 --- a/components/lazdebuggers/lazdebuggerfplldb/fplldbdebugger.pas +++ b/components/lazdebuggers/lazdebuggerfplldb/fplldbdebugger.pas @@ -131,6 +131,8 @@ type FDwarfLoaderThread: TDwarfLoaderThread; // cache last context FLastContext: array [0..MAX_CTX_CACHE-1] of TFpDbgSymbolScope; + FLockUnLoadDwarf: integer; + FUnLoadDwarfNeeded: Boolean; procedure DoBeginReceivingLines(Sender: TObject); procedure DoEndReceivingLines(Sender: TObject); protected @@ -144,6 +146,8 @@ type function HasDwarf: Boolean; function LoadDwarf: String; procedure UnLoadDwarf; + procedure LockUnLoadDwarf; + procedure UnLockUnLoadDwarf; function RequestCommand(const ACommand: TDBGCommand; const AParams: array of const; const ACallback: TMethod): Boolean; override; @@ -412,6 +416,7 @@ begin exit; end; + FpDebugger.LockUnLoadDwarf; Ctx := FpDebugger.GetInfoContextForContext(ALocals.ThreadId, ALocals.StackFrame); try if (Ctx = nil) or (Ctx.SymbolAtAddress = nil) then begin @@ -449,6 +454,7 @@ begin finally Ctx.ReleaseReference; ProcVal.ReleaseReference; + FpDebugger.UnLockUnLoadDwarf; end; end; @@ -799,6 +805,7 @@ begin debugln(['ProcessEvalList ']); inc(FWatchEvalLock); + FpDebugger.LockUnLoadDwarf; try // TODO: if the stack/thread is changed, registers will be wrong while (FpDebugger.FWatchEvalList.Count > 0) and (FEvaluationCmdObj = nil) and (not FWatchEvalCancel) do begin @@ -828,6 +835,7 @@ debugln(['ProcessEvalList ']); end; finally dec(FWatchEvalLock); + FpDebugger.UnLockUnLoadDwarf; end; end; @@ -1208,6 +1216,11 @@ end; procedure TFpLldbDebugger.UnLoadDwarf; begin + if FLockUnLoadDwarf > 0 then begin + FUnLoadDwarfNeeded := True; + exit; + end; + FUnLoadDwarfNeeded := False; debugln(DBG_VERBOSE, ['TFpLldbDebugger.UnLoadDwarf ']); FreeAndNil(FDwarfInfo); FreeAndNil(FImageLoaderList); @@ -1226,6 +1239,18 @@ begin end; end; +procedure TFpLldbDebugger.LockUnLoadDwarf; +begin + inc(FLockUnLoadDwarf); +end; + +procedure TFpLldbDebugger.UnLockUnLoadDwarf; +begin + dec(FLockUnLoadDwarf); + if (FLockUnLoadDwarf <= 0) and FUnLoadDwarfNeeded then + UnLoadDwarf; +end; + function TFpLldbDebugger.RequestCommand(const ACommand: TDBGCommand; const AParams: array of const; const ACallback: TMethod): Boolean; var @@ -1473,6 +1498,7 @@ begin FPrettyPrinter.AddressSize := ctx.SizeOfAddress; FPrettyPrinter.MemManager := ctx.MemManager; + LockUnLoadDwarf; PasExpr := TFpPascalExpression.Create(AExpression, Ctx); try if not IsWatchValueAlive then exit; @@ -1591,6 +1617,7 @@ DebugLn(DBG_VERBOSE, [ErrorHandler.ErrorAsString(PasExpr.Error)]); PasExpr.Free; FMemManager.DefaultContext := nil; Ctx.ReleaseReference; + UnLockUnLoadDwarf; end; end;