mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-04-19 09:09:32 +02:00
FpDebug: Introduce "Intrinsics functions" for watches. Add "length()" for string (dwarf-3) and array
This commit is contained in:
parent
f58a7bde79
commit
116b22ed72
@ -189,6 +189,7 @@ type
|
||||
function IsValidTypeCast: Boolean; override;
|
||||
function GetInternMemberByName(const AIndex: String): TFpValue;
|
||||
procedure Reset; override;
|
||||
function GetMemberCount: Integer; override;
|
||||
private
|
||||
FValue: String;
|
||||
FValueDone: Boolean;
|
||||
@ -240,10 +241,12 @@ type
|
||||
TFpValueDwarfV3FreePascalString = class(TFpValueDwarf) // short & ansi...
|
||||
private
|
||||
FValue: String;
|
||||
FValueDone: Boolean;
|
||||
FLowBound, FHighBound: Int64;
|
||||
FValueDone, FBoundsDone: Boolean;
|
||||
FDynamicCodePage: TSystemCodePage;
|
||||
function GetCodePage: TSystemCodePage;
|
||||
function ObtainDynamicCodePage(Addr: TFpDbgMemLocation; out Codepage: TSystemCodePage): Boolean;
|
||||
procedure CalcBounds;
|
||||
protected
|
||||
function IsValidTypeCast: Boolean; override;
|
||||
procedure Reset; override;
|
||||
@ -252,6 +255,7 @@ type
|
||||
function GetAsWideString: WideString; override;
|
||||
procedure SetAsCardinal(AValue: QWord); override;
|
||||
function GetAsCardinal: QWord; override;
|
||||
function GetMemberCount: Integer; override;
|
||||
public
|
||||
property DynamicCodePage: TSystemCodePage read GetCodePage;
|
||||
end;
|
||||
@ -1162,6 +1166,16 @@ begin
|
||||
FValueDone := False;
|
||||
end;
|
||||
|
||||
function TFpValueDwarfV2FreePascalShortString.GetMemberCount: Integer;
|
||||
var
|
||||
LenSym: TFpValueDwarf;
|
||||
begin
|
||||
LenSym := TFpValueDwarf(GetInternMemberByName('length'));
|
||||
assert(LenSym is TFpValueDwarf, 'LenSym is TFpValueDwarf');
|
||||
Result := LenSym.AsInteger;
|
||||
LenSym.ReleaseReference;
|
||||
end;
|
||||
|
||||
function TFpValueDwarfV2FreePascalShortString.GetFieldFlags: TFpValueFieldFlags;
|
||||
begin
|
||||
Result := inherited GetFieldFlags;
|
||||
@ -1524,7 +1538,7 @@ end;
|
||||
|
||||
function TFpValueDwarfV3FreePascalString.GetAsString: AnsiString;
|
||||
var
|
||||
t, t2: TFpSymbol;
|
||||
t: TFpSymbol;
|
||||
LowBound, HighBound, i: Int64;
|
||||
Addr, Addr2: TFpDbgMemLocation;
|
||||
WResult: WideString;
|
||||
@ -1545,11 +1559,6 @@ begin
|
||||
if t.NestedSymbolCount < 1 then // subrange type
|
||||
exit;
|
||||
|
||||
t2 := t.NestedSymbol[0]; // subrange type
|
||||
if not( (t2 is TFpSymbolDwarfType) and TFpSymbolDwarfType(t2).GetValueBounds(self, LowBound, HighBound) )
|
||||
then
|
||||
exit;
|
||||
|
||||
GetDwarfDataAddress(Addr);
|
||||
if (not IsValidLoc(Addr)) and
|
||||
(HasTypeCastInfo) and
|
||||
@ -1559,28 +1568,10 @@ begin
|
||||
if not IsReadableLoc(Addr) then
|
||||
exit;
|
||||
|
||||
assert((TypeInfo <> nil) and (TypeInfo.CompilationUnit <> nil) and (TypeInfo.CompilationUnit.DwarfSymbolClassMap is TFpDwarfFreePascalSymbolClassMapDwarf3), 'TFpValueDwarfV3FreePascalString.GetAsString: (Owner <> nil) and (Owner.CompilationUnit <> nil) and (TypeInfo.CompilationUnit.DwarfSymbolClassMap is TFpDwarfFreePascalSymbolClassMapDwarf3)');
|
||||
if (TFpDwarfFreePascalSymbolClassMapDwarf3(TypeInfo.CompilationUnit.DwarfSymbolClassMap).FCompilerVersion > 0) and
|
||||
(TFpDwarfFreePascalSymbolClassMapDwarf3(TypeInfo.CompilationUnit.DwarfSymbolClassMap).FCompilerVersion < $030100)
|
||||
then begin
|
||||
if t.Kind = skWideString then begin
|
||||
if (t2 is TFpSymbolDwarfTypeSubRange) and (LowBound = 1) then begin
|
||||
if (TFpSymbolDwarfTypeSubRange(t2).InformationEntry.GetAttribData(DW_AT_upper_bound, AttrData)) and
|
||||
(TFpSymbolDwarfTypeSubRange(t2).InformationEntry.AttribForm[AttrData.Idx] = DW_FORM_block1) and
|
||||
(IsReadableMem(Addr) and (LocToAddr(Addr) > AddressSize))
|
||||
then begin
|
||||
// fpc issue 0035359
|
||||
// read data and check for DW_OP_shr ?
|
||||
Addr2 := Addr;
|
||||
Addr2.Address := Addr2.Address - AddressSize;
|
||||
if Context.ReadSignedInt(Addr2, SizeVal(AddressSize), i) then begin
|
||||
if (i shr 1) = HighBound then
|
||||
HighBound := i;
|
||||
end
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
CalcBounds;
|
||||
LowBound := FLowBound;
|
||||
HighBound := FHighBound;
|
||||
|
||||
if HighBound < LowBound then
|
||||
exit; // empty string
|
||||
@ -1664,6 +1655,12 @@ begin
|
||||
Result := inherited GetAsCardinal;
|
||||
end;
|
||||
|
||||
function TFpValueDwarfV3FreePascalString.GetMemberCount: Integer;
|
||||
begin
|
||||
CalcBounds;
|
||||
Result := Max(0, FHighBound - FLowBound + 1);
|
||||
end;
|
||||
|
||||
function TFpValueDwarfV3FreePascalString.ObtainDynamicCodePage(Addr: TFpDbgMemLocation; out
|
||||
Codepage: TSystemCodePage): Boolean;
|
||||
var
|
||||
@ -1690,6 +1687,63 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TFpValueDwarfV3FreePascalString.CalcBounds;
|
||||
var
|
||||
t, t2: TFpSymbol;
|
||||
i: Int64;
|
||||
Addr, Addr2: TFpDbgMemLocation;
|
||||
AttrData: TDwarfAttribData;
|
||||
begin
|
||||
if FBoundsDone then
|
||||
exit;
|
||||
|
||||
FBoundsDone := True;
|
||||
FLowBound := 0;
|
||||
FHighBound := -1;
|
||||
|
||||
// get length
|
||||
t := TypeInfo;
|
||||
if t.NestedSymbolCount < 1 then // subrange type
|
||||
exit;
|
||||
|
||||
t2 := t.NestedSymbol[0]; // subrange type
|
||||
if not( (t2 is TFpSymbolDwarfType) and TFpSymbolDwarfType(t2).GetValueBounds(self, FLowBound, FHighBound) )
|
||||
then
|
||||
exit;
|
||||
|
||||
GetDwarfDataAddress(Addr);
|
||||
if (not IsValidLoc(Addr)) and
|
||||
(HasTypeCastInfo) and
|
||||
(svfOrdinal in TypeCastSourceValue.FieldFlags)
|
||||
then
|
||||
Addr := TargetLoc(TypeCastSourceValue.AsCardinal);
|
||||
if not IsReadableLoc(Addr) then
|
||||
exit;
|
||||
|
||||
assert((TypeInfo <> nil) and (TypeInfo.CompilationUnit <> nil) and (TypeInfo.CompilationUnit.DwarfSymbolClassMap is TFpDwarfFreePascalSymbolClassMapDwarf3), 'TFpValueDwarfV3FreePascalString.GetAsString: (Owner <> nil) and (Owner.CompilationUnit <> nil) and (TypeInfo.CompilationUnit.DwarfSymbolClassMap is TFpDwarfFreePascalSymbolClassMapDwarf3)');
|
||||
if (TFpDwarfFreePascalSymbolClassMapDwarf3(TypeInfo.CompilationUnit.DwarfSymbolClassMap).FCompilerVersion > 0) and
|
||||
(TFpDwarfFreePascalSymbolClassMapDwarf3(TypeInfo.CompilationUnit.DwarfSymbolClassMap).FCompilerVersion < $030100)
|
||||
then begin
|
||||
if t.Kind = skWideString then begin
|
||||
if (t2 is TFpSymbolDwarfTypeSubRange) and (FLowBound = 1) then begin
|
||||
if (TFpSymbolDwarfTypeSubRange(t2).InformationEntry.GetAttribData(DW_AT_upper_bound, AttrData)) and
|
||||
(TFpSymbolDwarfTypeSubRange(t2).InformationEntry.AttribForm[AttrData.Idx] = DW_FORM_block1) and
|
||||
(IsReadableMem(Addr) and (LocToAddr(Addr) > AddressSize))
|
||||
then begin
|
||||
// fpc issue 0035359
|
||||
// read data and check for DW_OP_shr ?
|
||||
Addr2 := Addr;
|
||||
Addr2.Address := Addr2.Address - AddressSize;
|
||||
if Context.ReadSignedInt(Addr2, SizeVal(AddressSize), i) then begin
|
||||
if (i shr 1) = FHighBound then
|
||||
FHighBound := i;
|
||||
end
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
{ TFpSymbolDwarfFreePascalDataProc }
|
||||
|
||||
function TFpSymbolDwarfFreePascalDataProc.GetLine: Cardinal;
|
||||
|
@ -298,6 +298,7 @@ type
|
||||
function GetFieldFlags: TFpValueFieldFlags; override;
|
||||
function GetAsString: AnsiString; override;
|
||||
function GetAsWideString: WideString; override;
|
||||
function GetMemberCount: Integer; override;
|
||||
public
|
||||
constructor Create(const AValue: AnsiString);
|
||||
end;
|
||||
@ -796,6 +797,11 @@ begin
|
||||
Result := GetAsString;
|
||||
end;
|
||||
|
||||
function TFpValueConstString.GetMemberCount: Integer;
|
||||
begin
|
||||
Result := Length(FValue);
|
||||
end;
|
||||
|
||||
constructor TFpValueConstString.Create(const AValue: AnsiString);
|
||||
begin
|
||||
inherited Create;
|
||||
|
@ -49,6 +49,9 @@ type
|
||||
|
||||
TSeparatorType = (ppstComma);
|
||||
|
||||
TFpIntrinsicPrefix = (ipExclamation, ipColon, ipNoPrefix);
|
||||
TFpIntrinsicFunc = (ifErrorNotFound, ifLength);
|
||||
|
||||
TFpPascalParserCallFunctionProc = function (AnExpressionPart: TFpPascalExpressionPart;
|
||||
AFunctionValue: TFpValue; ASelfValue: TFpValue; AParams: TFpPascalExpressionPartList;
|
||||
out AResult: TFpValue; var AnError: TFpError): boolean of object;
|
||||
@ -61,25 +64,27 @@ type
|
||||
FContext: TFpDbgSymbolScope;
|
||||
FFixPCharIndexAccess: Boolean;
|
||||
FHasPCharIndexAccess: Boolean;
|
||||
FIntrinsicPrefix: TFpIntrinsicPrefix;
|
||||
FOnFunctionCall: TFpPascalParserCallFunctionProc;
|
||||
FTextExpression: String;
|
||||
FExpressionPart: TFpPascalExpressionPart;
|
||||
FValid: Boolean;
|
||||
function GetResultValue: TFpValue;
|
||||
function GetValid: Boolean;
|
||||
procedure Parse;
|
||||
procedure SetError(AMsg: String); // deprecated;
|
||||
procedure SetError(AnErrorCode: TFpErrorCode; AData: array of const);
|
||||
procedure SetError(const AnErr: TFpError);
|
||||
function PosFromPChar(APChar: PChar): Integer;
|
||||
function LookupIntrinsic(AStart: PChar; ALen: Integer): TFpIntrinsicFunc;
|
||||
protected
|
||||
function GetDbgSymbolForIdentifier({%H-}AnIdent: String): TFpValue;
|
||||
function GetRegisterValue({%H-}AnIdent: String): TFpValue;
|
||||
property ExpressionPart: TFpPascalExpressionPart read FExpressionPart;
|
||||
property Context: TFpDbgSymbolScope read FContext;
|
||||
public
|
||||
constructor Create(ATextExpression: String; AContext: TFpDbgSymbolScope);
|
||||
constructor Create(ATextExpression: String; AContext: TFpDbgSymbolScope; ASkipParse: Boolean = False);
|
||||
destructor Destroy; override;
|
||||
procedure Parse;
|
||||
function DebugDump(AWithResults: Boolean = False): String;
|
||||
procedure ResetEvaluation;
|
||||
property TextExpression: String read FTextExpression;
|
||||
@ -89,6 +94,7 @@ type
|
||||
property HasPCharIndexAccess: Boolean read FHasPCharIndexAccess;
|
||||
// handle pchar as string (adjust index)
|
||||
property FixPCharIndexAccess: Boolean read FFixPCharIndexAccess write FFixPCharIndexAccess;
|
||||
property IntrinsicPrefix: TFpIntrinsicPrefix read FIntrinsicPrefix write FIntrinsicPrefix;
|
||||
// ResultValue
|
||||
// - May be a type, if expression is a type
|
||||
// - Only valid, as long as the expression is not destroyed
|
||||
@ -204,6 +210,22 @@ type
|
||||
function DoGetResultValue: TFpValue; override;
|
||||
end;
|
||||
|
||||
{ TFpPascalExpressionPartIntrinsic }
|
||||
TFpPascalExpressionPartBracketArgumentList = class;
|
||||
|
||||
TFpPascalExpressionPartIntrinsic = class(TFpPascalExpressionPartContainer)
|
||||
private
|
||||
FIntrinsic: TFpIntrinsicFunc;
|
||||
protected
|
||||
function DoLength(AParams: TFpPascalExpressionPartBracketArgumentList): TFpValue;
|
||||
|
||||
function DoGetResultValue: TFpValue; override;
|
||||
function DoGetResultValue(AParams: TFpPascalExpressionPartBracketArgumentList): TFpValue;
|
||||
public
|
||||
constructor Create(AExpression: TFpPascalExpression; AStartChar: PChar;
|
||||
AnEndChar: PChar; AnIntrinsic: TFpIntrinsicFunc);
|
||||
end;
|
||||
|
||||
TFpPascalExpressionPartConstant = class(TFpPascalExpressionPartContainer)
|
||||
end;
|
||||
|
||||
@ -1471,6 +1493,12 @@ begin
|
||||
end;
|
||||
|
||||
Itm0 := Items[0];
|
||||
|
||||
if Itm0 is TFpPascalExpressionPartIntrinsic then begin
|
||||
Result := TFpPascalExpressionPartIntrinsic(Itm0).DoGetResultValue(Self);
|
||||
exit;
|
||||
end;
|
||||
|
||||
tmp := Itm0.ResultValue;
|
||||
if (tmp = nil) or (not Expression.Valid) then
|
||||
exit;
|
||||
@ -1708,6 +1736,73 @@ begin
|
||||
Result := FExpression.GetRegisterValue(GetText);
|
||||
end;
|
||||
|
||||
{ TFpPascalExpressionPartIntrinsic }
|
||||
|
||||
function TFpPascalExpressionPartIntrinsic.DoLength(
|
||||
AParams: TFpPascalExpressionPartBracketArgumentList): TFpValue;
|
||||
var
|
||||
Itm: TFpPascalExpressionPart;
|
||||
Arg: TFpValue;
|
||||
ResLen: Integer;
|
||||
begin
|
||||
Result := nil;
|
||||
if (AParams.Count <> 2) then begin
|
||||
SetError('wrong argument count');
|
||||
exit;
|
||||
end;
|
||||
|
||||
Itm := AParams.Items[1];
|
||||
Arg := nil;
|
||||
if Itm <> nil then
|
||||
Arg := Itm.ResultValue;
|
||||
|
||||
if (Arg = nil) then begin
|
||||
SetError('argument not supported');
|
||||
exit;
|
||||
end;
|
||||
|
||||
ResLen := 0;
|
||||
case Arg.Kind of
|
||||
skChar: ResLen := 1;
|
||||
skString,
|
||||
skAnsiString,
|
||||
skWideString,
|
||||
skArray: ResLen := Arg.MemberCount;
|
||||
otherwise begin
|
||||
SetError('argument not supported');
|
||||
exit;
|
||||
end;
|
||||
|
||||
end;
|
||||
|
||||
Result := TFpValueConstNumber.Create(ResLen, True)
|
||||
end;
|
||||
|
||||
function TFpPascalExpressionPartIntrinsic.DoGetResultValue: TFpValue;
|
||||
begin
|
||||
Result := nil;
|
||||
SetError('wrong argument count');
|
||||
// this gets called, if an intrinsic has no () after it. I.e. no arguments and no empty brackets
|
||||
end;
|
||||
|
||||
function TFpPascalExpressionPartIntrinsic.DoGetResultValue(
|
||||
AParams: TFpPascalExpressionPartBracketArgumentList): TFpValue;
|
||||
begin
|
||||
Result := nil;
|
||||
case FIntrinsic of
|
||||
ifLength: Result := DoLength(AParams);
|
||||
end;
|
||||
// {$IFDEF WITH_REFCOUNT_DEBUG}Result.DbgRenameReference(nil, 'DoGetResultValue'){$ENDIF};
|
||||
end;
|
||||
|
||||
constructor TFpPascalExpressionPartIntrinsic.Create(
|
||||
AExpression: TFpPascalExpression; AStartChar: PChar; AnEndChar: PChar;
|
||||
AnIntrinsic: TFpIntrinsicFunc);
|
||||
begin
|
||||
inherited Create(AExpression, AStartChar, AnEndChar);
|
||||
FIntrinsic := AnIntrinsic;
|
||||
end;
|
||||
|
||||
{ TFpPascalExpressionPartConstantNumber }
|
||||
|
||||
function TFpPascalExpressionPartConstantNumber.DoGetResultValue: TFpValue;
|
||||
@ -1809,7 +1904,27 @@ var
|
||||
else AddPart(TFpPascalExpressionPartOperatorPlusMinus);
|
||||
end;
|
||||
|
||||
procedure AddIntrinsic(AnIntrinsic: TFpIntrinsicFunc);
|
||||
begin
|
||||
if AnIntrinsic = ifErrorNotFound then
|
||||
SetError('Unknown build-in')
|
||||
else
|
||||
NewPart := TFpPascalExpressionPartIntrinsic.Create(Self, CurPtr, TokenEndPtr-1, AnIntrinsic);
|
||||
end;
|
||||
|
||||
procedure AddIntrinsic;
|
||||
var
|
||||
intr: TFpIntrinsicFunc;
|
||||
begin
|
||||
while TokenEndPtr^ in ['a'..'z', 'A'..'Z', '_', '0'..'9', '$'] do
|
||||
inc(TokenEndPtr);
|
||||
intr := LookupIntrinsic(CurPtr, TokenEndPtr - CurPtr);
|
||||
AddIntrinsic(intr);
|
||||
end;
|
||||
|
||||
procedure AddIdentifier;
|
||||
var
|
||||
intr: TFpIntrinsicFunc;
|
||||
begin
|
||||
while TokenEndPtr^ in ['a'..'z', 'A'..'Z', '_', '0'..'9', '$'] do
|
||||
inc(TokenEndPtr);
|
||||
@ -1840,6 +1955,15 @@ var
|
||||
NewPart := TFpPascalExpressionPartOperatorUnaryNot.Create(Self, CurPtr, TokenEndPtr-1);
|
||||
end;
|
||||
end;
|
||||
|
||||
if (FIntrinsicPrefix = ipNoPrefix) then begin
|
||||
intr := LookupIntrinsic(CurPtr, TokenEndPtr - CurPtr);
|
||||
if intr <> ifErrorNotFound then begin
|
||||
AddIntrinsic(intr);
|
||||
exit;
|
||||
end;
|
||||
end;
|
||||
|
||||
if NewPart = nil then
|
||||
NewPart := TFpPascalExpressionPartIdentifier.Create(Self, CurPtr, TokenEndPtr-1);
|
||||
end;
|
||||
@ -2062,6 +2186,16 @@ begin
|
||||
|
||||
NewPart := nil;
|
||||
TokenEndPtr := CurPtr + 1;
|
||||
if (FIntrinsicPrefix = ipExclamation) and (CurPtr^ = '!') then begin
|
||||
inc(CurPtr);
|
||||
AddIntrinsic;
|
||||
end
|
||||
else
|
||||
if (FIntrinsicPrefix = ipColon) and (CurPtr^ = ':') then begin
|
||||
inc(CurPtr);
|
||||
AddIntrinsic;
|
||||
end
|
||||
else
|
||||
case CurPtr^ of
|
||||
'@' : AddPart(TFpPascalExpressionPartOperatorAddressOf);
|
||||
'^': AddRefOperator; // ^A may be #$01
|
||||
@ -2161,6 +2295,15 @@ begin
|
||||
Result := APChar - @FTextExpression[1] + 1;
|
||||
end;
|
||||
|
||||
function TFpPascalExpression.LookupIntrinsic(AStart: PChar; ALen: Integer
|
||||
): TFpIntrinsicFunc;
|
||||
begin
|
||||
Result := ifErrorNotFound;
|
||||
case ALen of
|
||||
6: if strlicomp(AStart, 'LENGTH', 6) = 0 then Result := ifLength;
|
||||
end;
|
||||
end;
|
||||
|
||||
function TFpPascalExpression.GetDbgSymbolForIdentifier(AnIdent: String): TFpValue;
|
||||
begin
|
||||
if FContext <> nil then
|
||||
@ -2192,14 +2335,15 @@ begin
|
||||
end;
|
||||
|
||||
constructor TFpPascalExpression.Create(ATextExpression: String;
|
||||
AContext: TFpDbgSymbolScope);
|
||||
AContext: TFpDbgSymbolScope; ASkipParse: Boolean);
|
||||
begin
|
||||
FContext := AContext;
|
||||
FContext.AddReference;
|
||||
FTextExpression := ATextExpression;
|
||||
FError := NoError;
|
||||
FValid := True;
|
||||
Parse;
|
||||
if not ASkipParse then
|
||||
Parse;
|
||||
end;
|
||||
|
||||
destructor TFpPascalExpression.Destroy;
|
||||
|
@ -3482,7 +3482,9 @@ begin
|
||||
if Context <> nil then begin
|
||||
PasExpr := nil;
|
||||
try
|
||||
PasExpr := TFpPascalExpression.Create(ABreakPoint.Expression, Context);
|
||||
PasExpr := TFpPascalExpression.Create(ABreakPoint.Expression, Context, True);
|
||||
PasExpr.IntrinsicPrefix := TFpDebugDebuggerProperties(GetProperties).IntrinsicPrefix;
|
||||
PasExpr.Parse;
|
||||
PasExpr.ResultValue; // trigger full validation
|
||||
if PasExpr.Valid and (svfBoolean in PasExpr.ResultValue.FieldFlags) and
|
||||
(not PasExpr.ResultValue.AsBool) // false => do not pause
|
||||
|
@ -30,8 +30,8 @@ unit FpDebugDebuggerUtils;
|
||||
interface
|
||||
|
||||
uses
|
||||
FpDbgUtil, FpdMemoryTools, {$ifdef FORCE_LAZLOGGER_DUMMY} LazLoggerDummy {$else} LazLoggerBase {$endif}, DbgIntfDebuggerBase, sysutils,
|
||||
Classes, syncobjs, Forms;
|
||||
FpDbgUtil, FpdMemoryTools, FpPascalParser, LazLoggerBase, DbgIntfDebuggerBase,
|
||||
sysutils, Classes, syncobjs, Forms;
|
||||
|
||||
type
|
||||
|
||||
@ -109,6 +109,7 @@ type
|
||||
FForceNewConsole: boolean;
|
||||
{$endif windows}
|
||||
FHandleDebugBreakInstruction: TFpInt3DebugBreakOptions;
|
||||
FIntrinsicPrefix: TFpIntrinsicPrefix;
|
||||
FMemLimits: TFpDebugDebuggerPropertiesMemLimits;
|
||||
FNextOnlyStopOnStartLine: boolean;
|
||||
procedure SetMemLimits(AValue: TFpDebugDebuggerPropertiesMemLimits);
|
||||
@ -128,6 +129,7 @@ type
|
||||
|
||||
property MemLimits: TFpDebugDebuggerPropertiesMemLimits read FMemLimits write SetMemLimits;
|
||||
property HandleDebugBreakInstruction: TFpInt3DebugBreakOptions read FHandleDebugBreakInstruction write FHandleDebugBreakInstruction default [dboIgnoreAll];
|
||||
property IntrinsicPrefix: TFpIntrinsicPrefix read FIntrinsicPrefix write FIntrinsicPrefix default ipExclamation;
|
||||
end;
|
||||
|
||||
|
||||
@ -368,6 +370,7 @@ begin
|
||||
{$endif windows}
|
||||
FMemLimits := TFpDebugDebuggerPropertiesMemLimits.Create;
|
||||
FHandleDebugBreakInstruction := [dboIgnoreAll];
|
||||
FIntrinsicPrefix := ipExclamation;
|
||||
end;
|
||||
|
||||
destructor TFpDebugDebuggerProperties.Destroy;
|
||||
@ -387,6 +390,7 @@ begin
|
||||
{$endif windows}
|
||||
FMemLimits.Assign(TFpDebugDebuggerProperties(Source).MemLimits);
|
||||
FHandleDebugBreakInstruction:=TFpDebugDebuggerProperties(Source).FHandleDebugBreakInstruction;
|
||||
FIntrinsicPrefix:=TFpDebugDebuggerProperties(Source).FIntrinsicPrefix;
|
||||
end;
|
||||
end;
|
||||
|
||||
|
@ -734,7 +734,9 @@ begin
|
||||
if ExpressionScope = nil then
|
||||
exit;
|
||||
|
||||
APasExpr := TFpPascalExpression.Create(FExpression, ExpressionScope);
|
||||
APasExpr := TFpPascalExpression.Create(FExpression, ExpressionScope, True);
|
||||
APasExpr.IntrinsicPrefix := TFpDebugDebuggerProperties(FDebugger.GetProperties).IntrinsicPrefix;
|
||||
APasExpr.Parse;
|
||||
try
|
||||
APasExpr.ResultValue; // trigger full validation
|
||||
if not APasExpr.Valid then
|
||||
@ -1121,7 +1123,9 @@ begin
|
||||
end;
|
||||
|
||||
PrettyPrinter := nil;
|
||||
APasExpr := TFpPascalExpression.Create(AnExpression, FExpressionScope);
|
||||
APasExpr := TFpPascalExpression.Create(AnExpression, FExpressionScope, True);
|
||||
APasExpr.IntrinsicPrefix := TFpDebugDebuggerProperties(FDebugger.GetProperties).IntrinsicPrefix;
|
||||
APasExpr.Parse;
|
||||
try
|
||||
if FAllowFunctions and (dfEvalFunctionCalls in FDebugger.EnabledFeatures) then
|
||||
APasExpr.OnFunctionCall := @DoWatchFunctionCall;
|
||||
@ -1154,7 +1158,9 @@ begin
|
||||
(not IsError(ResValue.LastError)) and (defClassAutoCast in AnEvalFlags)
|
||||
then begin
|
||||
if ResValue.GetInstanceClassName(CastName) then begin
|
||||
PasExpr2 := TFpPascalExpression.Create(CastName+'('+AnExpression+')', FExpressionScope);
|
||||
PasExpr2 := TFpPascalExpression.Create(CastName+'('+AnExpression+')', FExpressionScope, True);
|
||||
PasExpr2.IntrinsicPrefix := TFpDebugDebuggerProperties(FDebugger.GetProperties).IntrinsicPrefix;
|
||||
PasExpr2.Parse;
|
||||
PasExpr2.ResultValue;
|
||||
if PasExpr2.Valid then begin
|
||||
APasExpr.Free;
|
||||
@ -1389,7 +1395,9 @@ begin
|
||||
bpkData: begin
|
||||
CurContext := FDebugger.DbgController.CurrentProcess.FindSymbolScope(FThreadId, FStackFrame);
|
||||
if CurContext <> nil then begin
|
||||
WatchPasExpr := TFpPascalExpression.Create(FWatchData, CurContext);
|
||||
WatchPasExpr := TFpPascalExpression.Create(FWatchData, CurContext, True);
|
||||
WatchPasExpr.IntrinsicPrefix := TFpDebugDebuggerProperties(FDebugger.GetProperties).IntrinsicPrefix;
|
||||
WatchPasExpr.Parse;
|
||||
R := WatchPasExpr.ResultValue; // Address and Size
|
||||
// TODO: Cache current value
|
||||
if WatchPasExpr.Valid and IsTargetNotNil(R.Address) and R.GetSize(s) then begin
|
||||
|
Loading…
Reference in New Issue
Block a user