FpDebug: started DisplayFormat

git-svn-id: trunk@44896 -
This commit is contained in:
martin 2014-05-03 00:14:44 +00:00
parent 31b29671af
commit 6281c4adcf
3 changed files with 166 additions and 43 deletions

View File

@ -5,8 +5,8 @@ unit FpPascalBuilder;
interface interface
uses uses
Classes, SysUtils, DbgIntfBaseTypes, FpDbgInfo, FpdMemoryTools, FpErrorMessages, Classes, SysUtils, DbgIntfBaseTypes, DbgIntfDebuggerBase, FpDbgInfo, FpdMemoryTools,
LazLoggerBase; FpErrorMessages, LazLoggerBase;
type type
TTypeNameFlag = ( TTypeNameFlag = (
@ -39,18 +39,24 @@ type
TFpPascalPrettyPrinter = class TFpPascalPrettyPrinter = class
private private
FAddressSize: Integer; FAddressSize: Integer;
FMemManager: TFpDbgMemManager;
function InternalPrintValue(out APrintedValue: String; function InternalPrintValue(out APrintedValue: String;
AValue: TFpDbgValue; AValue: TFpDbgValue;
AnAddressSize: Integer; AnAddressSize: Integer;
AFlags: TFpPrettyPrintValueFlags; AFlags: TFpPrettyPrintValueFlags;
ANestLevel: Integer; AnIndent: String ANestLevel: Integer; AnIndent: String;
ADisplayFormat: TWatchDisplayFormat;
ARepaetCount: Integer = -1
): Boolean; ): Boolean;
public public
constructor Create(AnAddressSize: Integer); constructor Create(AnAddressSize: Integer);
function PrintValue(out APrintedValue: String; function PrintValue(out APrintedValue: String;
AValue: TFpDbgValue; AValue: TFpDbgValue;
AFlags: TFpPrettyPrintValueFlags = []): Boolean; ADisplayFormat: TWatchDisplayFormat = wdfDefault;
ARepaetCount: Integer = -1
): Boolean;
property AddressSize: Integer read FAddressSize write FAddressSize; property AddressSize: Integer read FAddressSize write FAddressSize;
property MemManager: TFpDbgMemManager read FMemManager write FMemManager;
end; end;
@ -422,7 +428,8 @@ end;
function TFpPascalPrettyPrinter.InternalPrintValue(out APrintedValue: String; function TFpPascalPrettyPrinter.InternalPrintValue(out APrintedValue: String;
AValue: TFpDbgValue; AnAddressSize: Integer; AFlags: TFpPrettyPrintValueFlags; AValue: TFpDbgValue; AnAddressSize: Integer; AFlags: TFpPrettyPrintValueFlags;
ANestLevel: Integer; AnIndent: String): Boolean; ANestLevel: Integer; AnIndent: String; ADisplayFormat: TWatchDisplayFormat;
ARepaetCount: Integer): Boolean;
function ResTypeName: String; function ResTypeName: String;
@ -438,15 +445,29 @@ function TFpPascalPrettyPrinter.InternalPrintValue(out APrintedValue: String;
s: String; s: String;
v: QWord; v: QWord;
begin begin
s := ResTypeName; if ((ADisplayFormat = wdfDefault) and (ANestLevel=0)) or // default for unested: with typename
v := AValue.AsCardinal; (ADisplayFormat = wdfStructure)
if v = 0 then then
APrintedValue := 'nil' s := ResTypeName
else else
APrintedValue := '$'+IntToHex(AValue.AsCardinal, AnAddressSize); s := '';
v := AValue.AsCardinal;
case ADisplayFormat of
wdfDecimal, wdfUnsigned: APrintedValue := IntToStr(AValue.AsCardinal);
wdfHex: APrintedValue := '$'+IntToHex(AValue.AsCardinal, AnAddressSize*2);
else begin //wdfPointer/Default ;
if v = 0 then
APrintedValue := 'nil'
else
APrintedValue := '$'+IntToHex(AValue.AsCardinal, AnAddressSize*2);
end;
end;
if s <> '' then if s <> '' then
APrintedValue := s + '(' + APrintedValue + ')'; APrintedValue := s + '(' + APrintedValue + ')';
if ADisplayFormat = wdfPointer then exit; // no data
if svfString in AValue.FieldFlags then if svfString in AValue.FieldFlags then
APrintedValue := APrintedValue + ' ' + AValue.AsString; APrintedValue := APrintedValue + ' ' + AValue.AsString;
@ -454,14 +475,50 @@ function TFpPascalPrettyPrinter.InternalPrintValue(out APrintedValue: String;
end; end;
procedure DoInt; procedure DoInt;
var
n: Integer;
begin begin
APrintedValue := IntToStr(AValue.AsInteger); case ADisplayFormat of
wdfUnsigned: APrintedValue := IntToStr(QWord(AValue.AsInteger));
wdfHex: begin
if svfSize in AValue.FieldFlags then
n := AValue.Size * 2
else begin
n := 16;
if QWord(AValue.AsInteger) <= high(Cardinal) then n := 8;
if QWord(AValue.AsInteger) <= high(Word) then n := 3;
if QWord(AValue.AsInteger) <= high(Byte) then n := 2;
end;
APrintedValue := '$'+IntToHex(QWord(AValue.AsInteger), n);
end;
// TODO wdfChar:
else
APrintedValue := IntToStr(AValue.AsInteger);
end;
Result := True; Result := True;
end; end;
procedure DoCardinal; procedure DoCardinal;
var
n: Integer;
begin begin
APrintedValue := IntToStr(AValue.AsCardinal); case ADisplayFormat of
wdfDecimal: APrintedValue := IntToStr(Int64(AValue.AsCardinal));
wdfHex: begin
if svfSize in AValue.FieldFlags then
n := AValue.Size * 2
else begin
n := 16;
if AValue.AsCardinal <= high(Cardinal) then n := 8;
if AValue.AsCardinal <= high(Word) then n := 4;
if AValue.AsCardinal <= high(Byte) then n := 2;
end;
APrintedValue := '$'+IntToHex(AValue.AsCardinal, n);
end;
// TODO wdfChar:
else
APrintedValue := IntToStr(AValue.AsCardinal);
end;
Result := True; Result := True;
end; end;
@ -546,6 +603,14 @@ function TFpPascalPrettyPrinter.InternalPrintValue(out APrintedValue: String;
Result := True; Result := True;
exit; exit;
end; end;
if ADisplayFormat = wdfPointer then begin
s := ResTypeName;
APrintedValue := '$'+IntToHex(AValue.AsCardinal, AnAddressSize*2);
if s <> '' then
APrintedValue := s + '(' + APrintedValue + ')';
Result := True;
exit;
end;
if ( (AValue.Kind in [skClass, skObject]) and (ppvSkipClassBody in AFlags) ) or if ( (AValue.Kind in [skClass, skObject]) and (ppvSkipClassBody in AFlags) ) or
( (AValue.Kind in [skRecord]) and (ppvSkipRecordBody in AFlags) ) ( (AValue.Kind in [skRecord]) and (ppvSkipRecordBody in AFlags) )
@ -554,7 +619,7 @@ function TFpPascalPrettyPrinter.InternalPrintValue(out APrintedValue: String;
case AValue.Kind of case AValue.Kind of
skRecord: APrintedValue := '{record:}' + APrintedValue; skRecord: APrintedValue := '{record:}' + APrintedValue;
skObject: APrintedValue := '{object:}' + APrintedValue; skObject: APrintedValue := '{object:}' + APrintedValue;
skClass: APrintedValue := '{class:}' + APrintedValue + '(' + '$'+IntToHex(AValue.AsCardinal, AnAddressSize) + ')'; skClass: APrintedValue := '{class:}' + APrintedValue + '(' + '$'+IntToHex(AValue.AsCardinal, AnAddressSize*2) + ')';
end; end;
Result := True; Result := True;
exit; exit;
@ -572,7 +637,7 @@ function TFpPascalPrettyPrinter.InternalPrintValue(out APrintedValue: String;
if (m = nil) or (m.Kind in [skProcedure, skFunction]) then if (m = nil) or (m.Kind in [skProcedure, skFunction]) then
continue; continue;
s := ''; s := '';
InternalPrintValue(s, m, AnAddressSize, fl, ANestLevel+1, AnIndent); InternalPrintValue(s, m, AnAddressSize, fl, ANestLevel+1, AnIndent, ADisplayFormat);
if m.DbgSymbol <> nil then if m.DbgSymbol <> nil then
s := m.DbgSymbol.Name + ' = ' + s; s := m.DbgSymbol.Name + ' = ' + s;
if APrintedValue = '' if APrintedValue = ''
@ -588,48 +653,96 @@ function TFpPascalPrettyPrinter.InternalPrintValue(out APrintedValue: String;
s: String; s: String;
i: Integer; i: Integer;
m: TFpDbgValue; m: TFpDbgValue;
c, d: Integer; Cnt, FullCnt, d: Integer;
begin begin
APrintedValue := ''; APrintedValue := '';
c := AValue.MemberCount; Cnt := AValue.MemberCount;
if (c = 0) and (svfOrdinal in AValue.FieldFlags) then begin // dyn array FullCnt := Cnt;
if (Cnt = 0) and (svfOrdinal in AValue.FieldFlags) then begin // dyn array
APrintedValue := 'nil'; APrintedValue := 'nil';
Result := True; Result := True;
exit; exit;
end; end;
if (ANestLevel > 2) then begin if (ANestLevel > 2) then begin
s := ResTypeName; s := ResTypeName;
APrintedValue := s+'(...)'; // TODO len and addr (dyn array) APrintedValue := s+'({'+IntToStr(FullCnt)+' elements})'; // TODO len and addr (dyn array)
Result := True; Result := True;
exit; exit;
end; end;
if (ANestLevel > 1) and (c > 5) then c := 5 if (ANestLevel > 1) and (Cnt > 3) then Cnt := 3
else if (ANestLevel > 0) and (c > 15) then c := 15 else if (ANestLevel > 0) and (Cnt > 10) then Cnt := 10
else if (c > 500) then c := 500; else if (Cnt > 300) then Cnt := 300;
d := 0; d := 0;
// TODO: use valueobject for bounds // TODO: use valueobject for bounds
if (AValue.IndexTypeCount > 0) and AValue.IndexType[0].HasBounds then if (AValue.IndexTypeCount > 0) and AValue.IndexType[0].HasBounds then
d := AValue.IndexType[0].OrdLowBound; d := AValue.IndexType[0].OrdLowBound;
for i := d to d + c - 1 do begin for i := d to d + Cnt - 1 do begin
m := AValue.Member[i]; m := AValue.Member[i];
if m <> nil then if m <> nil then
InternalPrintValue(s, m, AnAddressSize, AFlags, ANestLevel+1, AnIndent) InternalPrintValue(s, m, AnAddressSize, AFlags, ANestLevel+1, AnIndent, ADisplayFormat)
else else
s := '{error}'; s := '{error}';
if APrintedValue = '' if APrintedValue = ''
then APrintedValue := s then APrintedValue := s
else APrintedValue := APrintedValue + ', ' + s; else APrintedValue := APrintedValue + ', ' + s;
end; end;
if c < AValue.MemberCount then if Cnt < FullCnt then
APrintedValue := APrintedValue + ', ...'; APrintedValue := APrintedValue + ', {'+IntToStr(FullCnt-Cnt)+' more elements}';
APrintedValue := '(' + APrintedValue + ')'; APrintedValue := '(' + APrintedValue + ')';
Result := True; Result := True;
end; end;
var
MemAddr: TFpDbgMemLocation;
MemSize: Integer;
MemDest: array of Byte;
i: Integer;
begin begin
if ANestLevel > 0 then begin if ANestLevel > 0 then begin
AnIndent := AnIndent + ' '; AnIndent := AnIndent + ' ';
end; end;
if ADisplayFormat = wdfMemDump then begin
if FMemManager <> nil then begin
MemAddr := UnInitializedLoc;
if svfDataAddress in AValue.FieldFlags then begin
MemAddr := AValue.DataAddress;
MemSize := AValue.DataSize;
if MemSize = 0 then MemSize := 256;
end
else
if svfAddress in AValue.FieldFlags then begin
MemAddr := AValue.Address;
MemSize := AValue.Size;
end;
if IsTargetAddr(MemAddr) then begin
if MemSize < 32 then MemSize := 32;
SetLength(MemDest, MemSize);
if FMemManager.ReadMemory(MemAddr, MemSize, @MemDest[0]) then begin
APrintedValue := IntToHex(MemAddr.Address, AnAddressSize*2)+ ':' + LineEnding;
for i := 0 to high(MemDest) do begin
if (i > 0) and (i mod 16 = 0) then
APrintedValue := APrintedValue + LineEnding
else
if (i > 0) and (i mod 8 = 0) then
APrintedValue := APrintedValue + ' '
else
if (i > 0) then
APrintedValue := APrintedValue + ' ';
APrintedValue := APrintedValue + IntToHex(MemDest[i], 2);
end;
end
else begin
APrintedValue := 'Cannot read memory at address '+ IntToHex(MemAddr.Address, AnAddressSize*2);
end;
exit;
end;
end;
APrintedValue := 'Cannot read memory for expression';
exit
end;
Result := False; Result := False;
case AValue.Kind of case AValue.Kind of
skUnit: ; skUnit: ;
@ -666,9 +779,9 @@ begin
end; end;
function TFpPascalPrettyPrinter.PrintValue(out APrintedValue: String; AValue: TFpDbgValue; function TFpPascalPrettyPrinter.PrintValue(out APrintedValue: String; AValue: TFpDbgValue;
AFlags: TFpPrettyPrintValueFlags): Boolean; ADisplayFormat: TWatchDisplayFormat; ARepaetCount: Integer): Boolean;
begin begin
InternalPrintValue(APrintedValue, AValue, AddressSize, AFlags, 0, ''); InternalPrintValue(APrintedValue, AValue, AddressSize, [], 0, '', ADisplayFormat, ARepaetCount);
end; end;
end. end.

View File

@ -593,7 +593,7 @@ begin
else else
begin begin
FPrettyPrinter.AddressSize:=AContext.SizeOfAddress; FPrettyPrinter.AddressSize:=AContext.SizeOfAddress;
if FPrettyPrinter.PrintValue(AVal, APasExpr.ResultValue, []) then if FPrettyPrinter.PrintValue(AVal, APasExpr.ResultValue) then
begin begin
AWatchValue.Value := AVal; //IntToStr(APasExpr.ResultValue.AsInteger); AWatchValue.Value := AVal; //IntToStr(APasExpr.ResultValue.AsInteger);
AWatchValue.Validity := ddsValid; AWatchValue.Validity := ddsValid;

View File

@ -937,6 +937,8 @@ var
PasExpr: TFpPascalExpression; PasExpr: TFpPascalExpression;
ResValue: TFpDbgValue; ResValue: TFpDbgValue;
s: String; s: String;
DispFormat: TWatchDisplayFormat;
RepeatCnt: Integer;
function IsWatchValueAlive: Boolean; function IsWatchValueAlive: Boolean;
begin begin
@ -957,7 +959,7 @@ var
procedure DoPointer; procedure DoPointer;
begin begin
if not FPrettyPrinter.PrintValue(AResText, ResValue, []) then if not FPrettyPrinter.PrintValue(AResText, ResValue, DispFormat, RepeatCnt) then
exit; exit;
ATypeInfo := TDBGType.Create(skPointer, ResTypeName); ATypeInfo := TDBGType.Create(skPointer, ResTypeName);
ATypeInfo.Value.AsPointer := Pointer(ResValue.AsCardinal); // TODO: no cut off ATypeInfo.Value.AsPointer := Pointer(ResValue.AsCardinal); // TODO: no cut off
@ -966,7 +968,7 @@ var
procedure DoSimple; procedure DoSimple;
begin begin
if not FPrettyPrinter.PrintValue(AResText, ResValue, []) then if not FPrettyPrinter.PrintValue(AResText, ResValue, DispFormat, RepeatCnt) then
exit; exit;
ATypeInfo := TDBGType.Create(skSimple, ResTypeName); ATypeInfo := TDBGType.Create(skSimple, ResTypeName);
ATypeInfo.Value.AsString := AResText; ATypeInfo.Value.AsString := AResText;
@ -974,7 +976,7 @@ var
procedure DoEnum; procedure DoEnum;
begin begin
if not FPrettyPrinter.PrintValue(AResText, ResValue, []) then if not FPrettyPrinter.PrintValue(AResText, ResValue, DispFormat, RepeatCnt) then
exit; exit;
ATypeInfo := TDBGType.Create(skEnum, ResTypeName); ATypeInfo := TDBGType.Create(skEnum, ResTypeName);
ATypeInfo.Value.AsString := AResText; ATypeInfo.Value.AsString := AResText;
@ -982,7 +984,7 @@ var
procedure DoSet; procedure DoSet;
begin begin
if not FPrettyPrinter.PrintValue(AResText, ResValue, []) then if not FPrettyPrinter.PrintValue(AResText, ResValue, DispFormat, RepeatCnt) then
exit; exit;
ATypeInfo := TDBGType.Create(skSet, ResTypeName); ATypeInfo := TDBGType.Create(skSet, ResTypeName);
ATypeInfo.Value.AsString := AResText; ATypeInfo.Value.AsString := AResText;
@ -996,7 +998,7 @@ var
DBGType: TGDBType; DBGType: TGDBType;
f: TDBGField; f: TDBGField;
begin begin
if not FPrettyPrinter.PrintValue(AResText, ResValue, []) then if not FPrettyPrinter.PrintValue(AResText, ResValue, DispFormat, RepeatCnt) then
exit; exit;
ATypeInfo := TDBGType.Create(skRecord, ResTypeName); ATypeInfo := TDBGType.Create(skRecord, ResTypeName);
ATypeInfo.Value.AsString := AResText; ATypeInfo.Value.AsString := AResText;
@ -1010,7 +1012,7 @@ var
else else
begin begin
DBGType := TGDBType.Create(skSimple, ResTypeName(m)); DBGType := TGDBType.Create(skSimple, ResTypeName(m));
FPrettyPrinter.PrintValue(s2, m, []); FPrettyPrinter.PrintValue(s2, m, DispFormat, RepeatCnt);
DBGType.Value.AsString := s2; DBGType.Value.AsString := s2;
n := ''; n := '';
if m.DbgSymbol <> nil then n := m.DbgSymbol.Name; if m.DbgSymbol <> nil then n := m.DbgSymbol.Name;
@ -1033,7 +1035,7 @@ var
PasExpr2: TFpPascalExpression; PasExpr2: TFpPascalExpression;
begin begin
if (ResValue.Kind = skClass) and (ResValue.AsCardinal = 0) then begin if (ResValue.Kind = skClass) and (ResValue.AsCardinal = 0) then begin
if not FPrettyPrinter.PrintValue(AResText, ResValue, []) then if not FPrettyPrinter.PrintValue(AResText, ResValue, DispFormat, RepeatCnt) then
exit; exit;
ATypeInfo := TDBGType.Create(skSimple, ResTypeName); ATypeInfo := TDBGType.Create(skSimple, ResTypeName);
ATypeInfo.Value.AsString := AResText; ATypeInfo.Value.AsString := AResText;
@ -1042,7 +1044,7 @@ var
end; end;
CastName := ''; CastName := '';
if (defClassAutoCast in EvalFlags) then begin if (defClassAutoCast in EvalFlags) and (ResValue.Kind = skClass) then begin
if FMemManager.ReadAddress(ResValue.DataAddress, Ctx.SizeOfAddress, ClassAddr) then begin if FMemManager.ReadAddress(ResValue.DataAddress, Ctx.SizeOfAddress, ClassAddr) then begin
ClassAddr.Address := ClassAddr.Address + 3 * Ctx.SizeOfAddress; ClassAddr.Address := ClassAddr.Address + 3 * Ctx.SizeOfAddress;
if FMemManager.ReadAddress(ClassAddr, Ctx.SizeOfAddress, CNameAddr) then begin if FMemManager.ReadAddress(ClassAddr, Ctx.SizeOfAddress, CNameAddr) then begin
@ -1065,7 +1067,7 @@ var
end; end;
if not FPrettyPrinter.PrintValue(AResText, ResValue, []) then if not FPrettyPrinter.PrintValue(AResText, ResValue, DispFormat, RepeatCnt) then
exit; exit;
if CastName <> '' then AResText := CastName + AResText; if CastName <> '' then AResText := CastName + AResText;
//if PasExpr.ResultValue.Kind = skObject then //if PasExpr.ResultValue.Kind = skObject then
@ -1083,7 +1085,7 @@ var
else else
begin begin
DBGType := TGDBType.Create(skSimple, ResTypeName(m)); DBGType := TGDBType.Create(skSimple, ResTypeName(m));
FPrettyPrinter.PrintValue(s2, m, []); FPrettyPrinter.PrintValue(s2, m, DispFormat, RepeatCnt);
DBGType.Value.AsString := s2; DBGType.Value.AsString := s2;
n := ''; n := '';
if m.DbgSymbol <> nil then n := m.DbgSymbol.Name; if m.DbgSymbol <> nil then n := m.DbgSymbol.Name;
@ -1099,7 +1101,7 @@ var
procedure DoArray; procedure DoArray;
begin begin
if not FPrettyPrinter.PrintValue(AResText, ResValue, []) then if not FPrettyPrinter.PrintValue(AResText, ResValue, DispFormat, RepeatCnt) then
exit; exit;
ATypeInfo := TDBGType.Create(skArray, ResTypeName); ATypeInfo := TDBGType.Create(skArray, ResTypeName);
ATypeInfo.Value.AsString := AResText; ATypeInfo.Value.AsString := AResText;
@ -1122,14 +1124,21 @@ begin
// FMemReader.FStackFrame := CurrentStackFrame; // FMemReader.FStackFrame := CurrentStackFrame;
end; end;
if AWatchValue <> nil then if AWatchValue <> nil then begin
Ctx := GetInfoContextForContext(AWatchValue.ThreadId, AWatchValue.StackFrame) Ctx := GetInfoContextForContext(AWatchValue.ThreadId, AWatchValue.StackFrame);
else DispFormat := AWatchValue.DisplayFormat;
RepeatCnt := AWatchValue.RepeatCount;
end
else begin
Ctx := GetInfoContextForContext(CurrentThreadId, CurrentStackFrame); Ctx := GetInfoContextForContext(CurrentThreadId, CurrentStackFrame);
DispFormat := wdfDefault;
RepeatCnt := -1;
end;
if Ctx = nil then exit; if Ctx = nil then exit;
FMemManager.DefaultContext := Ctx; FMemManager.DefaultContext := Ctx;
FPrettyPrinter.AddressSize := ctx.SizeOfAddress; FPrettyPrinter.AddressSize := ctx.SizeOfAddress;
FPrettyPrinter.MemManager := ctx.MemManager;
PasExpr := TFpPascalExpression.Create(AExpression, Ctx); PasExpr := TFpPascalExpression.Create(AExpression, Ctx);
try try
@ -1187,7 +1196,8 @@ DebugLn(ErrorHandler.ErrorAsString(PasExpr.Error));
PasExpr.FixPCharIndexAccess := True; PasExpr.FixPCharIndexAccess := True;
PasExpr.ResetEvaluation; PasExpr.ResetEvaluation;
ResValue := PasExpr.ResultValue; ResValue := PasExpr.ResultValue;
if (ResValue=nil) or (not FPrettyPrinter.PrintValue(s, ResValue, [])) then s := 'Failed'; if (ResValue=nil) or (not FPrettyPrinter.PrintValue(s, ResValue, DispFormat, RepeatCnt)) then
s := 'Failed';
AResText := 'PChar: '+AResText+ LineEnding + 'String: '+s; AResText := 'PChar: '+AResText+ LineEnding + 'String: '+s;
end; end;