FPDebug: starting error msgs

git-svn-id: trunk@44196 -
This commit is contained in:
martin 2014-02-21 07:52:15 +00:00
parent 7e70fbf99b
commit da31678f3b
6 changed files with 223 additions and 16 deletions

1
.gitattributes vendored
View File

@ -1270,6 +1270,7 @@ components/fpdebug/fpdbgwinextra.pp svneol=native#text/pascal
components/fpdebug/fpdebug.lpk svneol=native#text/pascal components/fpdebug/fpdebug.lpk svneol=native#text/pascal
components/fpdebug/fpdebug.pas svneol=native#text/pascal components/fpdebug/fpdebug.pas svneol=native#text/pascal
components/fpdebug/fpdmemorytools.pas svneol=native#text/pascal components/fpdebug/fpdmemorytools.pas svneol=native#text/pascal
components/fpdebug/fperrormessages.pas svneol=native#text/pascal
components/fpdebug/fpimgreaderbase.pas svneol=native#text/pascal components/fpdebug/fpimgreaderbase.pas svneol=native#text/pascal
components/fpdebug/fpimgreaderelf.pas svneol=native#text/pascal components/fpdebug/fpimgreaderelf.pas svneol=native#text/pascal
components/fpdebug/fpimgreaderelftypes.pas svneol=native#text/pascal components/fpdebug/fpimgreaderelftypes.pas svneol=native#text/pascal

View File

@ -34,7 +34,7 @@ File(s) with other licenses (see also header in file(s):
(Any modifications/translations of this file are from duby) (Any modifications/translations of this file are from duby)
"/> "/>
<Files Count="21"> <Files Count="22">
<Item1> <Item1>
<Filename Value="fpdbgclasses.pp"/> <Filename Value="fpdbgclasses.pp"/>
<UnitName Value="FpDbgClasses"/> <UnitName Value="FpDbgClasses"/>
@ -120,6 +120,10 @@ File(s) with other licenses (see also header in file(s):
<Filename Value="fpdmemorytools.pas"/> <Filename Value="fpdmemorytools.pas"/>
<UnitName Value="FpdMemoryTools"/> <UnitName Value="FpdMemoryTools"/>
</Item21> </Item21>
<Item22>
<Filename Value="fperrormessages.pas"/>
<UnitName Value="fperrormessages"/>
</Item22>
</Files> </Files>
<Type Value="RunAndDesignTime"/> <Type Value="RunAndDesignTime"/>
<RequiredPkgs Count="3"> <RequiredPkgs Count="3">

View File

@ -10,7 +10,8 @@ uses
FpDbgClasses, FpDbgDisasX86, FpDbgDwarf, FpDbgDwarfConst, FpDbgLoader, FpDbgPETypes, FpDbgClasses, FpDbgDisasX86, FpDbgDwarf, FpDbgDwarfConst, FpDbgLoader, FpDbgPETypes,
FpDbgSymbols, FpDbgUtil, FpDbgWinExtra, FpImgReaderWinPE, FpImgReaderElf, FpDbgSymbols, FpDbgUtil, FpDbgWinExtra, FpImgReaderWinPE, FpImgReaderElf,
FpImgReaderElfTypes, FpImgReaderBase, FpPascalParser, macho, FpImgReaderMachoFile, FpImgReaderElfTypes, FpImgReaderBase, FpPascalParser, macho, FpImgReaderMachoFile,
FpImgReaderMacho, FpPascalBuilder, FpDbgInfo, FpdMemoryTools, LazarusPackageIntf; FpImgReaderMacho, FpPascalBuilder, FpDbgInfo, FpdMemoryTools, FpErrorMessages,
LazarusPackageIntf;
implementation implementation

View File

@ -0,0 +1,162 @@
unit FpErrorMessages;
{$mode objfpc}{$H+}
interface
uses
SysUtils, LazLoggerBase;
type
TFpErrorCode = Integer;
resourcestring
// %0:s is always linebreak
MsgfpErrAnyError = '%1:s';
MsgfpErrSymbolNotFound = 'Identifier not found: "%1:s"';
MsgfpErrNoMemberWithName = 'Member not found: %1:s';
const
fpErrAnyError = TFpErrorCode(1);
fpErrSymbolNotFound = TFpErrorCode(2);
fpErrNoMemberWithName = TFpErrorCode(3);
type
TFpError = record
ErrorCode: TFpErrorCode;
ErrorData: Array of TVarRec;
ErrorData2: Array of String;
end;
{ TErrorHandler }
{ TFpErrorHandler }
TFpErrorHandler = class
protected
function GetErrorRawString(AnErrorCode: TFpErrorCode): string;
public
function CreateError(AnErrorCode: TFpErrorCode; AData: array of const): TFpError;
function CreateError(AnErrorCode: TFpErrorCode; AnError: TFpError; AData: array of const): TFpError;
function ErrorAsString(AnError: TFpError): string;
function ErrorAsString(AnErrorCode: TFpErrorCode; AData: array of const): string;
end;
function GetFpErrorHandler: TFpErrorHandler;
procedure SetFpErrorHandler(AHandler: TFpErrorHandler);
property FpErrorHandler: TFpErrorHandler read GetFpErrorHandler write SetFpErrorHandler;
function IsFpError(AnError: TFpError): Boolean;
function FpErrorNone: TFpError;
implementation
var TheErrorHandler: TFpErrorHandler = nil;
function GetFpErrorHandler: TFpErrorHandler;
begin
if TheErrorHandler = nil then
TheErrorHandler := TFpErrorHandler.Create;
Result := TheErrorHandler;
end;
procedure SetFpErrorHandler(AHandler: TFpErrorHandler);
begin
FreeAndNil(TheErrorHandler);
TheErrorHandler := AHandler;
end;
function IsFpError(AnError: TFpError): Boolean;
begin
Result := AnError.ErrorCode <> 0;
end;
function FpErrorNone: TFpError;
begin
Result.ErrorCode := 0;
end;
{ TFpErrorHandler }
function TFpErrorHandler.GetErrorRawString(AnErrorCode: TFpErrorCode): string;
begin
case AnErrorCode of
fpErrAnyError: Result := MsgfpErrAnyError;
fpErrSymbolNotFound: Result := MsgfpErrSymbolNotFound;
fpErrNoMemberWithName: Result := MsgfpErrNoMemberWithName;
end;
end;
function TFpErrorHandler.CreateError(AnErrorCode: TFpErrorCode;
AData: array of const): TFpError;
var
i: Integer;
begin
Result.ErrorCode := AnErrorCode;
SetLength(Result.ErrorData, Length(AData));
SetLength(Result.ErrorData2, Length(AData));
for i := low(AData) to high(AData) do begin
Result.ErrorData[i] := AData[i];
if AData[i].VType = vtAnsiString then begin
Result.ErrorData2[i] := AnsiString(AData[i].VAnsiString);
Result.ErrorData[i].VAnsiString := Pointer(Result.ErrorData2[i]);
end;
end;
end;
function TFpErrorHandler.CreateError(AnErrorCode: TFpErrorCode; AnError: TFpError;
AData: array of const): TFpError;
var
i, j: Integer;
begin
Result.ErrorCode := AnErrorCode;
j := Length(AnError.ErrorData);
SetLength(Result.ErrorData, Length(AData) + j);
SetLength(Result.ErrorData2, Length(AData) + j);
for i := 0 to j - 1 do begin
Result.ErrorData2[i] := AnError.ErrorData2[i];
Result.ErrorData[i] := AnError.ErrorData[i];
end;
for i := low(AData) to high(AData) do begin
Result.ErrorData[j+i] := AData[i];
if AData[i].VType = vtAnsiString then begin
Result.ErrorData2[j+i] := AnsiString(AData[i].VAnsiString);
Result.ErrorData[j+i].VAnsiString := Pointer(Result.ErrorData2[j+i]);
end;
end;
end;
function TFpErrorHandler.ErrorAsString(AnError: TFpError): string;
var
RealData: Array of TVarRec;
i: Integer;
begin
Result := ErrorAsString(AnError.ErrorCode, AnError.ErrorData);
end;
function TFpErrorHandler.ErrorAsString(AnErrorCode: TFpErrorCode;
AData: array of const): string;
var
RealData: Array of TVarRec;
i: Integer;
s: String;
begin
Result := '';
if AnErrorCode = 0 then exit;
SetLength(RealData, Length(AData) + 1);
s := LineEnding;
RealData[0].VAnsiString := Pointer(s); // first arg is always line end
for i := 0 to Length(AData) - 1 do
RealData[i + 1] := AData[i];
s := GetErrorRawString(AnErrorCode);
if s = '' then s := 'Internal Error: ' + IntToStr(AnErrorCode);
Result := Format(s, RealData);
end;
finalization
FreeAndNil(TheErrorHandler);
end.

View File

@ -29,7 +29,8 @@ unit FpPascalParser;
interface interface
uses uses
Classes, sysutils, math, DbgIntfBaseTypes, FpDbgInfo, FpdMemoryTools, LazLoggerBase, LazClasses; Classes, sysutils, math, DbgIntfBaseTypes, FpDbgInfo, FpdMemoryTools, FpErrorMessages,
LazLoggerBase, LazClasses;
type type
@ -46,14 +47,15 @@ type
TFpPascalExpression = class TFpPascalExpression = class
private private
FError: String; FError: TFpError;
FContext: TDbgInfoAddressContext; FContext: TDbgInfoAddressContext;
FTextExpression: String; FTextExpression: String;
FExpressionPart: TFpPascalExpressionPart; FExpressionPart: TFpPascalExpressionPart;
FValid: Boolean; FValid: Boolean;
function GetResultValue: TDbgSymbolValue; function GetResultValue: TDbgSymbolValue;
procedure Parse; procedure Parse;
procedure SetError(AMsg: String); procedure SetError(AMsg: String); // deprecated;
procedure SetError(AnErrorCode: TFpErrorCode; AData: array of const);
function PosFromPChar(APChar: PChar): Integer; function PosFromPChar(APChar: PChar): Integer;
protected protected
function GetDbgSymbolForIdentifier({%H-}AnIdent: String): TDbgSymbol; function GetDbgSymbolForIdentifier({%H-}AnIdent: String): TDbgSymbol;
@ -63,7 +65,7 @@ type
constructor Create(ATextExpression: String; AContext: TDbgInfoAddressContext); constructor Create(ATextExpression: String; AContext: TDbgInfoAddressContext);
destructor Destroy; override; destructor Destroy; override;
function DebugDump(AWithResults: Boolean = False): String; function DebugDump(AWithResults: Boolean = False): String;
property Error: String read FError; property Error: TFpError read FError;
property Valid: Boolean read FValid; property Valid: Boolean read FValid;
// ResultValue // ResultValue
// - May be a type, if expression is a type // - May be a type, if expression is a type
@ -88,8 +90,9 @@ type
procedure SetEndChar(AValue: PChar); procedure SetEndChar(AValue: PChar);
procedure SetParent(AValue: TFpPascalExpressionPartContainer); procedure SetParent(AValue: TFpPascalExpressionPartContainer);
procedure SetStartChar(AValue: PChar); procedure SetStartChar(AValue: PChar);
procedure SetError(AMsg: String = ''); procedure SetError(AMsg: String = ''); // deprecated;
procedure SetError(APart: TFpPascalExpressionPart; AMsg: String = ''); procedure SetError(APart: TFpPascalExpressionPart; AMsg: String = ''); // deprecated;
procedure SetError(AnErrorCode: TFpErrorCode; AData: array of const);
protected protected
function DebugText(AIndent: String; {%H-}AWithResults: Boolean): String; virtual; // Self desc only function DebugText(AIndent: String; {%H-}AWithResults: Boolean): String; virtual; // Self desc only
function DebugDump(AIndent: String; AWithResults: Boolean): String; virtual; function DebugDump(AIndent: String; AWithResults: Boolean): String; virtual;
@ -1149,8 +1152,10 @@ var
begin begin
Result := nil; Result := nil;
DbgSymbol := FExpression.GetDbgSymbolForIdentifier(GetText); DbgSymbol := FExpression.GetDbgSymbolForIdentifier(GetText);
if DbgSymbol = nil then if DbgSymbol = nil then begin
SetError(fpErrSymbolNotFound, [GetText]);
exit; exit;
end;
Result := DbgSymbol.Value; Result := DbgSymbol.Value;
if Result = nil then begin if Result = nil then begin
@ -1352,11 +1357,21 @@ end;
procedure TFpPascalExpression.SetError(AMsg: String); procedure TFpPascalExpression.SetError(AMsg: String);
begin begin
FValid := False; if FError.ErrorCode <> 0 then begin
FError := AMsg; DebugLn(['Skipping error ', AMsg]);
FValid := False;
exit;
end;
SetError(fpErrAnyError, [AMsg]);
DebugLn(['PARSER ERROR ', AMsg]); DebugLn(['PARSER ERROR ', AMsg]);
end; end;
procedure TFpPascalExpression.SetError(AnErrorCode: TFpErrorCode; AData: array of const);
begin
FValid := False;
FError := FpErrorHandler.CreateError(AnErrorCode, AData);
end;
function TFpPascalExpression.PosFromPChar(APChar: PChar): Integer; function TFpPascalExpression.PosFromPChar(APChar: PChar): Integer;
begin begin
Result := APChar - @FTextExpression[1] + 1; Result := APChar - @FTextExpression[1] + 1;
@ -1375,6 +1390,7 @@ constructor TFpPascalExpression.Create(ATextExpression: String;
begin begin
FContext := AContext; FContext := AContext;
FTextExpression := ATextExpression; FTextExpression := ATextExpression;
FError := FpErrorNone;
FValid := True; FValid := True;
Parse; Parse;
end; end;
@ -1388,7 +1404,7 @@ end;
function TFpPascalExpression.DebugDump(AWithResults: Boolean): String; function TFpPascalExpression.DebugDump(AWithResults: Boolean): String;
begin begin
Result := 'TFpPascalExpression: ' + FTextExpression + LineEnding + Result := 'TFpPascalExpression: ' + FTextExpression + LineEnding +
'Valid: ' + dbgs(FValid) + ' Error: "' + FError + '"'+ LineEnding 'Valid: ' + dbgs(FValid) + ' Error: "' + dbgs(FError.ErrorCode) + '"'+ LineEnding
; ;
if FExpressionPart <> nil then if FExpressionPart <> nil then
Result := Result + FExpressionPart.DebugDump(' ', AWithResults); Result := Result + FExpressionPart.DebugDump(' ', AWithResults);
@ -1476,6 +1492,11 @@ begin
else Self.SetError(AMsg); else Self.SetError(AMsg);
end; end;
procedure TFpPascalExpressionPart.SetError(AnErrorCode: TFpErrorCode; AData: array of const);
begin
FExpression.SetError(AnErrorCode, AData);
end;
procedure TFpPascalExpressionPart.Init; procedure TFpPascalExpressionPart.Init;
begin begin
// //
@ -2051,9 +2072,12 @@ begin
// Todo unit // Todo unit
if (tmp.Kind in [skClass, skRecord, skObject]) then begin if (tmp.Kind in [skClass, skRecord, skObject]) then begin
Result := tmp.MemberByName[Items[1].GetText]; Result := tmp.MemberByName[Items[1].GetText];
if Result <> nil then if Result = nil then begin
Result.AddReference{$IFDEF WITH_REFCOUNT_DEBUG}(nil, 'DoGetResultValue'){$ENDIF}; SetError(fpErrNoMemberWithName, [Items[1].GetText]);
Assert((Result=nil) or (Result.DbgSymbol=nil)or(Result.DbgSymbol.SymbolType=stValue), 'member is value'); exit;
end;
Result.AddReference{$IFDEF WITH_REFCOUNT_DEBUG}(nil, 'DoGetResultValue'){$ENDIF};
Assert((Result.DbgSymbol=nil)or(Result.DbgSymbol.SymbolType=stValue), 'member is value');
end; end;
end; end;

View File

@ -15,7 +15,7 @@ uses
Classes, sysutils, math, FpdMemoryTools, FpDbgInfo, FpDbgClasses, GDBMIDebugger, Classes, sysutils, math, FpdMemoryTools, FpDbgInfo, FpDbgClasses, GDBMIDebugger,
DbgIntfBaseTypes, DbgIntfDebuggerBase, GDBMIMiscClasses, DbgIntfBaseTypes, DbgIntfDebuggerBase, GDBMIMiscClasses,
GDBTypeInfo, maps, LCLProc, Forms, FpDbgLoader, FpDbgDwarf, FpDbgDwarfConst, LazLoggerBase, GDBTypeInfo, maps, LCLProc, Forms, FpDbgLoader, FpDbgDwarf, FpDbgDwarfConst, LazLoggerBase,
LazLoggerProfiling, LazClasses, FpPascalParser, FpPascalBuilder; LazLoggerProfiling, LazClasses, FpPascalParser, FpPascalBuilder, FpErrorMessages;
type type
@ -1454,6 +1454,21 @@ begin
PasExpr := TFpPascalExpression.Create(AExpression, Ctx); PasExpr := TFpPascalExpression.Create(AExpression, Ctx);
try try
if not IsWatchValueAlive then exit; if not IsWatchValueAlive then exit;
PasExpr.ResultValue; // trigger evaluate // and check errors
if not IsWatchValueAlive then exit;
if not PasExpr.Valid then begin
DebugLn(FpErrorHandler.ErrorAsString(PasExpr.Error));
if PasExpr.Error.ErrorCode <> fpErrAnyError then begin
Result := True;
AResText := FpErrorHandler.ErrorAsString(PasExpr.Error);;
if AWatchValue <> nil then begin;
AWatchValue.Value := AResText;
AWatchValue.Validity := ddsError;
end;
exit;
end;
end;
if not (PasExpr.Valid and (PasExpr.ResultValue <> nil)) then if not (PasExpr.Valid and (PasExpr.ResultValue <> nil)) then
exit; // TODO handle error exit; // TODO handle error