DBG: watch dyn array, show some values

git-svn-id: trunk@36292 -
This commit is contained in:
martin 2012-03-24 17:38:22 +00:00
parent 7e6f03810d
commit 71d29ac07e
5 changed files with 255 additions and 46 deletions

View File

@ -980,6 +980,9 @@ type
FTypeName: String; FTypeName: String;
FTypeDeclaration: String; FTypeDeclaration: String;
FDBGValue: TDBGValue; FDBGValue: TDBGValue;
FBoundHigh: Integer;
FBoundLow: Integer;
FLen: Integer;
procedure Init; virtual; procedure Init; virtual;
public public
Value: TDBGValue; Value: TDBGValue;
@ -993,7 +996,10 @@ type
property Attributes: TDBGSymbolAttributes read FAttributes; property Attributes: TDBGSymbolAttributes read FAttributes;
property TypeName: String read FTypeName; // Name/Alias as in type section. One pascal token, or empty property TypeName: String read FTypeName; // Name/Alias as in type section. One pascal token, or empty
property TypeDeclaration: String read FTypeDeclaration; // Declaration (for array, set, enum, ..) property TypeDeclaration: String read FTypeDeclaration; // Declaration (for array, set, enum, ..)
property Members: TStrings read FMembers; property Members: TStrings read FMembers; // Set & ENUM
property Len: Integer read FLen; // Array
property BoundLow: Integer read FBoundLow; // Array
property BoundHigh: Integer read FBoundHigh; // Array
property Result: TDBGType read FResult; property Result: TDBGType read FResult;
end; end;
{%endregion ^^^^^ Debug Info ^^^^^ } {%endregion ^^^^^ Debug Info ^^^^^ }

View File

@ -68,6 +68,7 @@ resourcestring
drsInspectColWidthMethAddress = 'Method address column'; drsInspectColWidthMethAddress = 'Method address column';
drsUseInstanceClassType = 'Use Instance class type'; drsUseInstanceClassType = 'Use Instance class type';
drsLen = 'Len=%d: ';
implementation implementation

View File

@ -132,6 +132,10 @@ begin
if cmbExpression.Items.IndexOf(S) = -1 if cmbExpression.Items.IndexOf(S) = -1
then cmbExpression.Items.Insert(0, S); then cmbExpression.Items.Insert(0, S);
tbModify.Enabled := True; tbModify.Enabled := True;
if (DBGType <> nil) and (DBGType.Attributes * [saArray, saDynArray] <> []) and (DBGType.Len >= 0)
then R := Format(drsLen, [DBGType.Len]) + LineEnding + R;
end end
else else
tbModify.Enabled := False; tbModify.Enabled := False;

View File

@ -34,7 +34,7 @@ unit GDBTypeInfo;
interface interface
uses uses
Classes, SysUtils, Debugger, LclProc, LazLoggerBase, DebugUtils, GDBMIMiscClasses; Classes, SysUtils, Debugger, LclProc, math, LazLoggerBase, DebugUtils, GDBMIMiscClasses;
(* (*
ptype = { ptype = {
@ -320,16 +320,18 @@ type
gtpsSimplePointer, gtpsSimplePointer,
gtpsClass, gtpsClassAutoCast, gtpsClassPointer, gtpsClassAncestor, gtpsClass, gtpsClassAutoCast, gtpsClassPointer, gtpsClassAncestor,
gtpsArray, gtpsArray,
gtpsEvalExpr, gtpsEvalExpr, gtpsEvalExprArray, gtpsEvalExprDynArray, gtpsEvalExprDynArrayGetData,
gtpsFinished gtpsFinished
); );
TGDBTypeProcessRequest = TGDBTypeProcessRequest =
(gptrPTypeExpr, gptrWhatisExpr, gptrPTypeOfWhatis, (gptrPTypeExpr, gptrWhatisExpr, gptrPTypeOfWhatis,
gptrPTypeExprDeRef, gptrPTypeExprDeDeRef, // "Foo^", "Foo^^" for Foo=Object, or &Object gptrPTypeExprDeRef, gptrPTypeExprDeDeRef, // "Foo^", "Foo^^" for Foo=Object, or &Object
gptrEvalExpr, gptrEvalExprDeRef, gptrEvalExprCast, gptrEvalExpr, gptrEvalExprDeRef, gptrEvalExprCast,
gptrEvalExpr2, gptrEvalExprDeRef2, gptrEvalExprCast2, // used by MaybeString gptrEvalExpr2, gptrEvalExprDeRef2, gptrEvalExprCast2, // used by MaybeString
gptrPtypeCustomFixCast, gptrPtypeCustomAutoCast, gptrPtypeCustomAutoCast2, gptrPtypeCustomFixCast, gptrPtypeCustomAutoCast, gptrPtypeCustomAutoCast2,
gptrInstanceClassName gptrInstanceClassName,
gptrPtypeCustomEval
); );
TGDBTypeProcessRequests = set of TGDBTypeProcessRequest; TGDBTypeProcessRequests = set of TGDBTypeProcessRequest;
@ -337,6 +339,7 @@ type
private private
FInternalTypeName: string; FInternalTypeName: string;
private private
FEvalStarted: Boolean;
FExpression, FOrigExpression: string; FExpression, FOrigExpression: string;
FHasStringExprEvaluatedAsText: Boolean; FHasStringExprEvaluatedAsText: Boolean;
FCreationFlags: TGDBTypeCreationFlags; FCreationFlags: TGDBTypeCreationFlags;
@ -350,7 +353,9 @@ type
FFirstProcessingSubType, FNextProcessingSubType: TGDBType; FFirstProcessingSubType, FNextProcessingSubType: TGDBType;
FStringExprEvaluatedAsText: String; FStringExprEvaluatedAsText: String;
FTypeInfoAncestor: TGDBType; FTypeInfoAncestor: TGDBType;
FTypeInfoArrayExpression: TGDBType;
FArrayIndexValues: Array of TGDBType;
FArrayIndexValueLimit: Integer;
// Gdb-Requests // Gdb-Requests
FEvalError: boolean; FEvalError: boolean;
@ -1957,6 +1962,7 @@ function TGDBType.RequireRequests(ARequired: TGDBTypeProcessRequests; ACustomDat
gptrPtypeCustomFixCast, gptrPtypeCustomAutoCast, gptrPtypeCustomAutoCast2: gptrPtypeCustomFixCast, gptrPtypeCustomAutoCast, gptrPtypeCustomAutoCast2:
Result := GdbCmdPType + ACustomData; Result := GdbCmdPType + ACustomData;
gptrInstanceClassName: Result := GdbCmdEvaluate+Quote('(^^^char('+FExpression+')^+3)^'); gptrInstanceClassName: Result := GdbCmdEvaluate+Quote('(^^^char('+FExpression+')^+3)^');
gptrPtypeCustomEval: Result := GdbCmdEvaluate+Quote(ACustomData);
end; end;
end; end;
@ -2008,6 +2014,7 @@ begin
FOrigExpression := FExpression; FOrigExpression := FExpression;
FCreationFlags := AFlags; FCreationFlags := AFlags;
FExprEvaluateFormat := AFormat; FExprEvaluateFormat := AFormat;
FEvalStarted := False;
FEvalRequest := nil; FEvalRequest := nil;
FFirstProcessingSubType := nil; FFirstProcessingSubType := nil;
FNextProcessingSubType := nil; FNextProcessingSubType := nil;
@ -2015,13 +2022,18 @@ begin
FHasExprEvaluatedAsText := False; FHasExprEvaluatedAsText := False;
FHasAutoTypeCastFix := False; FHasAutoTypeCastFix := False;
FAutoTypeCastName := ''; FAutoTypeCastName := '';
FArrayIndexValueLimit := 5;
end; end;
destructor TGDBType.Destroy; destructor TGDBType.Destroy;
var
i: Integer;
begin begin
inherited Destroy; inherited Destroy;
FreeAndNil(FTypeInfoAncestor); FreeAndNil(FTypeInfoAncestor);
FreeAndNil(FTypeInfoArrayExpression); for i := 0 to Length(FArrayIndexValues) - 1 do
FArrayIndexValues[i].Free;
FArrayIndexValues := nil;
FreeAndNil(FParsedExpression); FreeAndNil(FParsedExpression);
end; end;
@ -2492,33 +2504,198 @@ var
{%endregion * Simple * } {%endregion * Simple * }
{%region * EvaluateExpression * } {%region * EvaluateExpression * }
function GetParsedFromResult(AGdbDesc, AField: String): String;
var
ResultList: TGDBMINameValueList;
begin
ResultList := TGDBMINameValueList.Create(AGdbDesc);
Result := ResultList.Values[AField];
//FTextValue := DeleteEscapeChars(FTextValue);
ResultList.Free;
end;
procedure ParseFromResult(AGdbDesc, AField: String);
begin
FExprEvaluatedAsText := GetParsedFromResult(AGdbDesc, AField);
FHasExprEvaluatedAsText := True;
end;
procedure ParseFromResultForStrFixed(AGdbDesc, AField: String);
begin
FStringExprEvaluatedAsText := GetParsedFromResult(AGdbDesc, AField);
FHasStringExprEvaluatedAsText := True;
end;
procedure EvaluateExpressionDynArrayGetData;
var
i, m: Integer;
s: String;
begin
FProcessState := gtpsEvalExprDynArrayGetData;
if (FLen <= 0) or (FArrayIndexValueLimit <= 0) then begin
Result := True;
exit;
end;
if (Length(FArrayIndexValues) > 0) then begin
FExprEvaluatedAsText := '';
for i := 0 to Length(FArrayIndexValues) - 1 do begin
s := FArrayIndexValues[i].ExprEvaluatedAsText;
if (pos(' ', s) > 0) or (pos(',', s) > 0) then
s := '('+s+')';
if i > 0 then
FExprEvaluatedAsText := FExprEvaluatedAsText + ', ';
FExprEvaluatedAsText := FExprEvaluatedAsText + s;
end;
if FArrayIndexValueLimit < FLen then
FExprEvaluatedAsText := FExprEvaluatedAsText + ', ...';
Result := True;
exit;
end;
if (FExprEvaluatedAsText <> '') and
(FExprEvaluatedAsText[1] = '{') // gdb returned array data
then begin
if (FLen = 0) or
((Length(FExprEvaluatedAsText) > 1) and (FExprEvaluatedAsText[2] <> '}') )
then begin
Result := True;
exit;
end;
end;
// Get Data
m := Min(FArrayIndexValueLimit, FLen);
SetLength(FArrayIndexValues, m);
for i := 0 to m-1 do begin
FArrayIndexValues[i] := TGDBType.CreateForExpression(FExpression+'['+IntToStr(i)+']',
FCreationFlags + [gtcfExprEvaluate]);
if i = 0
then FArrayIndexValues[i].FArrayIndexValueLimit := FArrayIndexValueLimit - 2
else FArrayIndexValues[i].FArrayIndexValueLimit := FArrayIndexValueLimit - 3;
AddSubType(FArrayIndexValues[i]);
end;
end;
procedure EvaluateExpressionDynArray;
begin
FProcessState := gtpsEvalExprDynArray;
if FExprEvaluateFormat <> wdfDefault then begin;
Result := True;
exit;
end;
FBoundLow := -1;
FBoundHigh := -1;
FLen := -1;
if not RequireRequests([gptrPtypeCustomEval], '^longint('+FExpression+')[-1]') then exit;
if not IsReqError(gptrPtypeCustomEval, False) then begin
FBoundLow := 0;
FBoundHigh := StrToIntDef(GetParsedFromResult(FReqResults[gptrPtypeCustomEval].Result.GdbDescription, 'value'), -1);
FLen := FBoundHigh + 1;
end;
if (saInternalPointer in FAttributes) then begin
if not RequireRequests([gptrEvalExprDeRef]) then exit;
if not IsReqError(gptrEvalExprDeRef, False) then begin
ParseFromResult(FReqResults[gptrEvalExprDeRef].Result.GdbDescription, 'value');
EvaluateExpressionDynArrayGetData;
exit;
end;
end;
if (saRefParam in FAttributes) then begin
if not RequireRequests([gptrEvalExprCast]) then exit;
if not IsReqError(gptrEvalExprCast, False) then begin
ParseFromResult(FReqResults[gptrEvalExprCast].Result.GdbDescription, 'value');
EvaluateExpressionDynArrayGetData;
exit;
end;
end;
if not RequireRequests([gptrEvalExpr]) then exit;
if not IsReqError(gptrEvalExpr, False) then begin
ParseFromResult(FReqResults[gptrEvalExpr].Result.GdbDescription, 'value');
EvaluateExpressionDynArrayGetData;
exit;
end;
if FLen > 0 then begin
EvaluateExpressionDynArrayGetData;
exit;
end;
// TODO: set Validity = error
ParseFromResult(FReqResults[gptrEvalExpr].Result.GdbDescription, 'msg');
Result := True;
end;
procedure EvaluateExpressionArray;
var
PTypeResult: TGDBPTypeResult;
begin
FProcessState := gtpsEvalExprArray;
if FExprEvaluateFormat <> wdfDefault then begin;
Result := True;
exit;
end;
PTypeResult := FReqResults[gptrPTypeExpr].Result;
FBoundLow := PCLenToInt(PTypeResult.BoundLow);
FBoundHigh := PCLenToInt(PTypeResult.BoundHigh);
FLen := PCLenToInt(PTypeResult.BoundHigh) - PCLenToInt(PTypeResult.BoundLow) + 1;
if (saInternalPointer in FAttributes) then begin
if not RequireRequests([gptrEvalExprDeRef]) then exit;
if not IsReqError(gptrEvalExprDeRef, False) then begin
ParseFromResult(FReqResults[gptrEvalExprDeRef].Result.GdbDescription, 'value');
Result := True;
exit;
end;
end;
if (saRefParam in FAttributes) then begin
if not RequireRequests([gptrEvalExprCast]) then exit;
if not IsReqError(gptrEvalExprCast, False) then begin
ParseFromResult(FReqResults[gptrEvalExprCast].Result.GdbDescription, 'value');
Result := True;
exit;
end;
end;
if not RequireRequests([gptrEvalExpr]) then exit;
if not IsReqError(gptrEvalExpr, False) then begin
ParseFromResult(FReqResults[gptrEvalExpr].Result.GdbDescription, 'value');
Result := True;
exit;
end;
// TODO: set Validity = error
ParseFromResult(FReqResults[gptrEvalExpr].Result.GdbDescription, 'msg');
Result := True;
end;
procedure EvaluateExpression; procedure EvaluateExpression;
procedure ParseFromResult(AGdbDesc, AField: String);
var
ResultList: TGDBMINameValueList;
begin
ResultList := TGDBMINameValueList.Create(AGdbDesc);
FExprEvaluatedAsText := ResultList.Values[AField];
FHasExprEvaluatedAsText := True;
//FTextValue := DeleteEscapeChars(FTextValue);
ResultList.Free;
end;
procedure ParseFromResultForStrFixed(AGdbDesc, AField: String);
var
ResultList: TGDBMINameValueList;
begin
ResultList := TGDBMINameValueList.Create(AGdbDesc);
FStringExprEvaluatedAsText := ResultList.Values[AField];
FHasStringExprEvaluatedAsText := True;
//FTextValue := DeleteEscapeChars(FTextValue);
ResultList.Free;
end;
begin begin
FProcessState := gtpsEvalExpr; FProcessState := gtpsEvalExpr;
if not(gtcfExprEvaluate in FCreationFlags) then begin if not(gtcfExprEvaluate in FCreationFlags) then begin
Result := True; Result := True;
exit; exit;
end; end;
if saDynArray in FAttributes then begin
EvaluateExpressionDynArray;
exit;
end;
if saArray in FAttributes then begin
EvaluateExpressionArray;
exit;
end;
if FExprEvaluateFormat <> wdfDefault then begin; if FExprEvaluateFormat <> wdfDefault then begin;
Result := True; Result := True;
exit; exit;
@ -2772,7 +2949,7 @@ var
if FParsedExpression = nil if FParsedExpression = nil
then FParsedExpression := TGDBExpression.Create(FExpression); then FParsedExpression := TGDBExpression.Create(FExpression);
// Does not set FLastEvalRequest, so there can be no MergeSubProcessRequests // Does not set FLastEvalRequest
if FParsedExpression.NeedValidation(FEvalRequest) if FParsedExpression.NeedValidation(FEvalRequest)
then exit; then exit;
@ -2789,7 +2966,15 @@ var
while SubType <> nil do begin while SubType <> nil do begin
if (FEvalRequest = nil) if (FEvalRequest = nil)
then FEvalRequest := SubType.FEvalRequest then FEvalRequest := SubType.FEvalRequest
else FLastEvalRequest^.Next := SubType.FEvalRequest;; else if FLastEvalRequest <> nil
then FLastEvalRequest^.Next := SubType.FEvalRequest
else begin
// Find last req
FLastEvalRequest := FEvalRequest;
while (FLastEvalRequest^.Next <> nil) do
FLastEvalRequest := FLastEvalRequest^.Next;
FLastEvalRequest^.Next := SubType.FEvalRequest;
end;
FLastEvalRequest := SubType.FLastEvalRequest; FLastEvalRequest := SubType.FLastEvalRequest;
SubType := SubType.FNextProcessingSubType; SubType := SubType.FNextProcessingSubType;
end; end;
@ -2799,20 +2984,22 @@ var
var var
SubType, PrevSubType: TGDBType; SubType, PrevSubType: TGDBType;
begin begin
Result := False;
PrevSubType := nil; PrevSubType := nil;
SubType := FFirstProcessingSubType; SubType := FFirstProcessingSubType;
Result := SubType = nil;
while SubType <> nil do begin while SubType <> nil do begin
DebugLnEnter(DBGMI_TYPE_INFO, ['>>Enter Sub-Request']);
if SubType.ProcessExpression then begin if SubType.ProcessExpression then begin
Result := True;
if PrevSubType = nil if PrevSubType = nil
then FFirstProcessingSubType := SubType.FNextProcessingSubType then FFirstProcessingSubType := SubType.FNextProcessingSubType
else PrevSubType.FNextProcessingSubType := SubType.FNextProcessingSubType; else PrevSubType.FNextProcessingSubType := SubType.FNextProcessingSubType;
end; end
PrevSubType := SubType; else
PrevSubType := SubType;
SubType := SubType.FNextProcessingSubType; SubType := SubType.FNextProcessingSubType;
DebugLnExit(DBGMI_TYPE_INFO, ['>>Leave Sub-Request']);
end; end;
Result := FFirstProcessingSubType = nil;
end; end;
var var
@ -2840,21 +3027,25 @@ begin
OldReqMade := FProccesReuestsMade; OldReqMade := FProccesReuestsMade;
case FProcessState of case FProcessState of
gtpsInitial: ProcessInitial; gtpsInitial: ProcessInitial;
gtpsInitialSimple: ProcessInitialSimple; gtpsInitialSimple: ProcessInitialSimple;
gtpsSimplePointer: ProcessSimplePointer; gtpsSimplePointer: ProcessSimplePointer;
gtpsClass: ProcessClass; gtpsClass: ProcessClass;
gtpsClassAutoCast: ProcessClassAutoCast; gtpsClassAutoCast: ProcessClassAutoCast;
gtpsClassPointer: ProcessClassPointer; gtpsClassPointer: ProcessClassPointer;
gtpsClassAncestor: ProcessClassAncestor; gtpsClassAncestor: ProcessClassAncestor;
gtpsArray: ProcessArray; gtpsArray: ProcessArray;
gtpsEvalExpr: EvaluateExpression; gtpsEvalExpr: EvaluateExpression;
gtpsEvalExprArray: EvaluateExpressionArray;
gtpsEvalExprDynArray: EvaluateExpressionDynArray;
gtpsEvalExprDynArrayGetData: EvaluateExpressionDynArrayGetData;
end; end;
FreeAndNil(Lines); FreeAndNil(Lines);
if Result and not(FProcessState = gtpsEvalExpr) if Result and not(FEvalStarted)
then begin then begin
Result := False; Result := False;
FEvalStarted := True;
EvaluateExpression; EvaluateExpression;
end; end;

View File

@ -38,7 +38,7 @@ unit WatchesDlg;
interface interface
uses uses
Classes, Forms, Controls, math, LazLoggerBase, Classes, Forms, Controls, math, sysutils, LazLoggerBase,
IDEWindowIntf, Menus, ComCtrls, ActnList, IDEImagesIntf, LazarusIDEStrConsts, DebuggerStrConst, IDEWindowIntf, Menus, ComCtrls, ActnList, IDEImagesIntf, LazarusIDEStrConsts, DebuggerStrConst,
Debugger, DebuggerDlg, BaseDebugManager; Debugger, DebuggerDlg, BaseDebugManager;
@ -660,8 +660,15 @@ begin
WatchValue := AWatch.Values[GetThreadId, GetStackframe]; WatchValue := AWatch.Values[GetThreadId, GetStackframe];
if (WatchValue <> nil) and if (WatchValue <> nil) and
( (GetSelectedSnapshot = nil) or not(WatchValue.Validity in [ddsUnknown, ddsEvaluating, ddsRequested]) ) ( (GetSelectedSnapshot = nil) or not(WatchValue.Validity in [ddsUnknown, ddsEvaluating, ddsRequested]) )
then AItem.SubItems[0] := ClearMultiline(WatchValue.Value) then begin
else AItem.SubItems[0] := '<not evaluated>'; if (WatchValue.TypeInfo <> nil) and
(WatchValue.TypeInfo.Attributes * [saArray, saDynArray] <> []) and
(WatchValue.TypeInfo.Len >= 0)
then AItem.SubItems[0] := Format(drsLen, [WatchValue.TypeInfo.Len]) + ClearMultiline(WatchValue.Value)
else AItem.SubItems[0] := ClearMultiline(WatchValue.Value);
end
else
AItem.SubItems[0] := '<not evaluated>';
exclude(FStateFlags, wdsfUpdating); exclude(FStateFlags, wdsfUpdating);
if wdsfNeedDeleteCurrent in FStateFlags then if wdsfNeedDeleteCurrent in FStateFlags then
popDeleteClick(nil); popDeleteClick(nil);