mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-05-14 16:52:44 +02:00
296 lines
8.3 KiB
ObjectPascal
296 lines
8.3 KiB
ObjectPascal
unit FpDebugFpcConvVariantNormalizer;
|
|
|
|
{$mode objfpc}{$H+}
|
|
|
|
interface
|
|
|
|
uses
|
|
Classes, SysUtils, FpDebugValueConvertors, FpDebugDebuggerBase,
|
|
FpDebugStringConstants, LazDebuggerValueConverter, LazDebuggerIntf, FpDbgInfo,
|
|
FpDbgUtil, FpErrorMessages, FpDbgDwarf, FpdMemoryTools, DbgIntfBaseTypes;
|
|
|
|
type
|
|
|
|
(**** Display variant as single/simple value ****)
|
|
|
|
|
|
{ TFpDbgValueConverterVariantNormalizer }
|
|
|
|
TFpDbgValueConverterVariantNormalizer = class(TFpDbgValueConverter)
|
|
protected
|
|
//function GetSettingsFrame: ILazDbgValueConverterSettingsFrameIntf; override; // TConverterSettingsFrameBase
|
|
public
|
|
class function GetName: String; override;
|
|
function GetRegistryEntry: TLazDbgValueConvertRegistryEntryClass; override;
|
|
function NeedConversionLimit: Boolean; override;
|
|
function CanHandleValue(ASourceValue: TFpValue; AnFpDebugger: TFpDebugDebuggerBase): Boolean; override;
|
|
function ConvertValue(ASourceValue: TFpValue;
|
|
AnFpDebugger: TFpDebugDebuggerBase;
|
|
AnExpressionScope: TFpDbgSymbolScope;
|
|
var AnResData: IDbgWatchDataIntf
|
|
): TFpValue; override;
|
|
end;
|
|
|
|
{ TFpDbgValueConverterVariantNormalizerRegistryEntry }
|
|
|
|
TFpDbgValueConverterVariantNormalizerRegistryEntry = class(TFpDbgValueConverterRegistryEntry)
|
|
public
|
|
class function GetConvertorClass: TClass; override;
|
|
end;
|
|
|
|
|
|
implementation
|
|
|
|
{ TFpDbgValueConverterVariantNormalizer }
|
|
|
|
class function TFpDbgValueConverterVariantNormalizer.GetName: String;
|
|
begin
|
|
Result := drsConverterNormalizeVariant;
|
|
end;
|
|
|
|
function TFpDbgValueConverterVariantNormalizer.GetRegistryEntry: TLazDbgValueConvertRegistryEntryClass;
|
|
begin
|
|
Result := TFpDbgValueConverterVariantNormalizerRegistryEntry;
|
|
end;
|
|
|
|
function TFpDbgValueConverterVariantNormalizer.NeedConversionLimit: Boolean;
|
|
begin
|
|
Result := False;
|
|
end;
|
|
|
|
function TFpDbgValueConverterVariantNormalizer.CanHandleValue(
|
|
ASourceValue: TFpValue; AnFpDebugger: TFpDebugDebuggerBase): Boolean;
|
|
var
|
|
m, m2: TFpValue;
|
|
begin
|
|
Result := (ASourceValue.Kind = skRecord) and (AnFpDebugger.DbgController.CurrentProcess <> nil);
|
|
if (not Result) then
|
|
exit;
|
|
|
|
if AnFpDebugger.DbgController.CurrentProcess.Mode = dm32 then
|
|
Result := (ASourceValue.DataSize.Size = 16)
|
|
else
|
|
Result := (ASourceValue.DataSize.Size = 24);
|
|
|
|
if (not Result) then
|
|
exit;
|
|
|
|
if (ASourceValue.MemberCount = 1) then begin
|
|
m := ASourceValue.Member[0];
|
|
Result := (m <> nil);
|
|
if not Result then begin
|
|
exit;
|
|
m.ReleaseReference;
|
|
end;
|
|
|
|
m2 := m.Member[-1];
|
|
m.ReleaseReference;
|
|
Result := (m2 <> nil) and (m2.FieldFlags * [svfInteger, svfCardinal, svfOrdinal] <> []);
|
|
m2.ReleaseReference;
|
|
|
|
exit;
|
|
end
|
|
else
|
|
begin
|
|
m := ASourceValue.MemberByName['vtype'];
|
|
Result := (m <> nil);
|
|
m.ReleaseReference;
|
|
exit;
|
|
end;
|
|
|
|
Result := False;
|
|
end;
|
|
|
|
function TFpDbgValueConverterVariantNormalizer.ConvertValue(
|
|
ASourceValue: TFpValue; AnFpDebugger: TFpDebugDebuggerBase;
|
|
AnExpressionScope: TFpDbgSymbolScope; var AnResData: IDbgWatchDataIntf
|
|
): TFpValue;
|
|
|
|
procedure ReturnSourceValue;
|
|
begin
|
|
Result.ReleaseReference;
|
|
ASourceValue.AddReference;
|
|
Result := ASourceValue;
|
|
end;
|
|
|
|
procedure ReturnNil;
|
|
begin
|
|
Result.ReleaseReference;
|
|
Result := nil;
|
|
end;
|
|
|
|
procedure HandleAnsiString;
|
|
var
|
|
Addr: TFpDbgMemLocation;
|
|
sz: Integer;
|
|
SLen: Int64;
|
|
Str: string;
|
|
begin
|
|
if (Result = nil) then begin
|
|
ReturnSourceValue;
|
|
exit;
|
|
end;
|
|
if (Result.Kind <> skPointer) then
|
|
exit;
|
|
|
|
Addr := Result.DerefAddress;
|
|
if not IsTargetNotNil(Addr) then
|
|
exit;
|
|
|
|
sz := AnExpressionScope.LocationContext.SizeOfAddress;
|
|
Addr.Address := Addr.Address - sz;
|
|
AnExpressionScope.LocationContext.ReadSignedInt(Addr, SizeVal(sz), SLen);
|
|
if IsError(AnExpressionScope.LocationContext.LastMemError) then begin
|
|
AnResData.CreateError('<Error reading string>');
|
|
ReturnNil;
|
|
exit;
|
|
end;
|
|
|
|
Addr.Address := Addr.Address + sz;
|
|
if SLen > AnExpressionScope.LocationContext.MemManager.MemLimits.MaxStringLen then
|
|
SLen := AnExpressionScope.LocationContext.MemManager.MemLimits.MaxStringLen;
|
|
SetLength(Str, SLen);
|
|
if SLen > 0 then
|
|
AnExpressionScope.LocationContext.ReadMemory(Addr, SizeVal(SLen), @Str[1]);
|
|
if IsError(AnExpressionScope.LocationContext.LastMemError) then
|
|
AnResData.CreateError('<Error reading string>')
|
|
else
|
|
AnResData.CreateString(Str);
|
|
ReturnNil;
|
|
end;
|
|
|
|
var
|
|
m, m2, vtype: TFpValue;
|
|
discr: Int64;
|
|
i: Integer;
|
|
t: TFpSymbol;
|
|
OldResData: IDbgWatchDataIntf;
|
|
begin
|
|
Result := nil;
|
|
|
|
OldResData := AnResData;
|
|
AnResData := AnResData.CreateVariantValue();
|
|
t := ASourceValue.TypeInfo;
|
|
if (t <> nil) then
|
|
OldResData.SetTypeName(t.Name);
|
|
|
|
|
|
if ASourceValue.MemberCount = 1 then begin
|
|
// dwarf 3
|
|
m := ASourceValue.Member[0];
|
|
if m = nil then begin
|
|
ReturnSourceValue;
|
|
exit;
|
|
end;
|
|
|
|
vtype := m.Member[-1];
|
|
if vtype = nil then begin
|
|
m.ReleaseReference;
|
|
ReturnSourceValue;
|
|
exit;
|
|
end;
|
|
|
|
discr := vtype.AsInteger;
|
|
try
|
|
for i := 0 to m.MemberCount - 1 do begin
|
|
m2 := m.Member[i];
|
|
try
|
|
if (m2 <> nil) and
|
|
(m2.DbgSymbol is TFpSymbolDwarfTypeVariant) and
|
|
(TFpSymbolDwarfTypeVariant(m2.DbgSymbol).MatchesDiscr(discr)) and
|
|
(m2.MemberCount = 1)
|
|
then begin
|
|
Result := m2.Member[0];
|
|
|
|
case discr of
|
|
0: if Result = nil then AnResData.CreatePrePrinted('<Empty>');
|
|
1: if Result = nil then AnResData.CreatePrePrinted('<Null>');
|
|
256: HandleAnsiString;
|
|
otherwise
|
|
if Result = nil then ReturnSourceValue;
|
|
end;
|
|
|
|
exit;
|
|
end;
|
|
finally
|
|
m2.ReleaseReference;
|
|
end;
|
|
end;
|
|
finally
|
|
m.ReleaseReference;
|
|
vtype.ReleaseReference;
|
|
end;
|
|
end
|
|
else begin
|
|
// dwarf 2
|
|
vtype := ASourceValue.MemberByName['vtype'];
|
|
try
|
|
i := vtype.AsInteger;
|
|
case i of
|
|
0: AnResData.CreatePrePrinted('<Empty>');
|
|
1: AnResData.CreatePrePrinted('<Null>');
|
|
2: Result := ASourceValue.MemberByName['VSMALLINT'];
|
|
3: Result := ASourceValue.MemberByName['VINTEGER'];
|
|
4: Result := ASourceValue.MemberByName['VSINGLE'];
|
|
5: Result := ASourceValue.MemberByName['VDOUBLE'];
|
|
6: Result := ASourceValue.MemberByName['VCURRENCY'];
|
|
7: Result := ASourceValue.MemberByName['VDATE'];
|
|
8: Result := ASourceValue.MemberByName['VOLESTR'];
|
|
9: Result := ASourceValue.MemberByName['VDISPATCH'];
|
|
10: Result := ASourceValue.MemberByName['VERROR'];
|
|
11: Result := ASourceValue.MemberByName['VBOOLEAN'];
|
|
//12: varVariant
|
|
13: Result := ASourceValue.MemberByName['VUNKNOWN'];
|
|
//14: varDecimal
|
|
//15??
|
|
16: Result := ASourceValue.MemberByName['VSHORTINT'];
|
|
17: Result := ASourceValue.MemberByName['VBYTE'];
|
|
18: Result := ASourceValue.MemberByName['VWORD'];
|
|
19: Result := ASourceValue.MemberByName['VLONGWORD'];
|
|
20: Result := ASourceValue.MemberByName['VINT64'];
|
|
21: Result := ASourceValue.MemberByName['VQWORD'];
|
|
22: Result := ASourceValue.MemberByName['VWORD'];
|
|
//
|
|
36: Result := ASourceValue.MemberByName['VRECORD'];
|
|
//72
|
|
256: Result := ASourceValue.MemberByName['VSTRING'];
|
|
257: Result := ASourceValue.MemberByName['VANY'];
|
|
258: Result := ASourceValue.MemberByName['VUSTRING'];
|
|
//258: varUString
|
|
8192: Result := ASourceValue.MemberByName['VARRAY'];
|
|
16384: Result := ASourceValue.MemberByName['VPOINTER'];
|
|
end;
|
|
|
|
if Result = nil then begin
|
|
ReturnSourceValue;
|
|
end
|
|
else
|
|
case i of
|
|
256: begin
|
|
HandleAnsiString;
|
|
exit;
|
|
end;
|
|
end;
|
|
finally
|
|
vtype.ReleaseReference;
|
|
end;
|
|
exit;
|
|
end;
|
|
|
|
if Result = nil then
|
|
ReturnSourceValue;
|
|
end;
|
|
|
|
{ TFpDbgValueConverterVariantNormalizerRegistryEntry }
|
|
|
|
class function TFpDbgValueConverterVariantNormalizerRegistryEntry.GetConvertorClass: TClass;
|
|
begin
|
|
Result := TFpDbgValueConverterVariantNormalizer;
|
|
end;
|
|
|
|
initialization
|
|
ValueConverterRegistry.Add(TFpDbgValueConverterVariantNormalizerRegistryEntry);
|
|
|
|
end.
|
|
|