mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-04-28 22:15:57 +02:00
314 lines
11 KiB
ObjectPascal
314 lines
11 KiB
ObjectPascal
unit FpErrorMessages;
|
|
|
|
{$mode objfpc}{$H+}
|
|
|
|
interface
|
|
|
|
uses
|
|
SysUtils, variants, 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';
|
|
MsgfpErrorNotAStructure = 'Cannot get member "%1:s" from none structure type: %2:s';
|
|
|
|
MsgfpErrPasParserInvalidExpression = 'Invalid Expression';
|
|
MsgfpErrPasParserUnexpectedToken = 'Unexpected token ''%1:s'' at pos %2:d';
|
|
MsgfpErrPasParserMissingExprAfterComma = 'Expected Expression after Comma, but found closing bracket %1:s';
|
|
MsgfpErrPasParserMissingIndexExpression = 'Expected Expression but found closing bracket: %1:s';
|
|
MsgfpErrInvalidNumber = 'Can''t parse number: %1:s';
|
|
MsgfpErrCannotDereferenceType = 'Can not dereference Expression "%1:s"';
|
|
MsgfpErrTypeHasNoIndex = 'Not a type or Array. Cannot access indexed element on expression %1:s';
|
|
// 100 memreader error
|
|
MsgfpErrfpErrFailedReadMem = 'Failed to read data from target mem';
|
|
MsgfpErrCanNotReadInvalidMem = 'Failed to read data from invalid location';
|
|
MsgfpErrCanNotReadMemAtAddr = 'Failed to read Mem at Address $%1:x';
|
|
// 200 LocationParser
|
|
MsgfpErrLocationParser = 'Internal Error: Can not calculate location.';
|
|
MsgfpErrLocationParserMemRead = '%1:s (while calculating location)'; // Pass on nested error
|
|
MsgfpErrLocationParserInit = 'Internal Error: Can not calculate location. (Init)';
|
|
MsgfpErrLocationParserMinStack = 'Not enough elements on stack.'; // internally used
|
|
MsgfpErrLocationParserNoAddressOnStack = 'Not an address on stack'; // internally used
|
|
|
|
const
|
|
fpErrNoError = TFpErrorCode(0); // not an error
|
|
fpErrAnyError = TFpErrorCode(1);
|
|
|
|
fpErrSymbolNotFound = TFpErrorCode(2);
|
|
fpErrNoMemberWithName = TFpErrorCode(3);
|
|
fpErrorNotAStructure = TFpErrorCode(4);
|
|
|
|
fpErrPasParserInvalidExpression = TFpErrorCode(24);
|
|
fpErrPasParserUnexpectedToken = TFpErrorCode(25);
|
|
fpErrPasParserMissingExprAfterComma = TFpErrorCode(26);
|
|
fpErrPasParserMissingIndexExpression = TFpErrorCode(27);
|
|
fpErrInvalidNumber = TFpErrorCode(28);
|
|
fpErrCannotDereferenceType = TFpErrorCode(29);
|
|
fpErrTypeHasNoIndex = TFpErrorCode(30);
|
|
|
|
// 100 memreader error
|
|
fpErrFailedReadMem = TFpErrorCode(100);
|
|
fpErrCanNotReadInvalidMem = TFpErrorCode(101);
|
|
fpErrCanNotReadMemAtAddr = TFpErrorCode(102);
|
|
|
|
// 200 LocationParser
|
|
fpErrLocationParser = TFpErrorCode(200);
|
|
fpErrLocationParserMemRead = TFpErrorCode(201);
|
|
fpErrLocationParserInit = TFpErrorCode(202);
|
|
fpErrLocationParserMinStack = TFpErrorCode(203);
|
|
fpErrLocationParserNoAddressOnStack = TFpErrorCode(204);
|
|
type
|
|
|
|
TFpError = array of record
|
|
ErrorCode: TFpErrorCode;
|
|
ErrorData: Array of TVarRec;
|
|
ErrorData2: Array of
|
|
record
|
|
ansi: Ansistring;
|
|
wide: widestring;
|
|
uni: unicodestring;
|
|
vari: variant;
|
|
case integer of
|
|
1: (ext: Extended);
|
|
2: (cur: Currency);
|
|
3: (short: shortstring);
|
|
4: (i64: int64);
|
|
5: (qw: QWord);
|
|
end;
|
|
end;
|
|
|
|
{ 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; virtual;
|
|
function ErrorAsString(AnErrorCode: TFpErrorCode; AData: array of const): string; virtual;
|
|
end;
|
|
|
|
function GetFpErrorHandler: TFpErrorHandler;
|
|
procedure SetFpErrorHandler(AHandler: TFpErrorHandler);
|
|
|
|
property ErrorHandler: TFpErrorHandler read GetFpErrorHandler write SetFpErrorHandler;
|
|
|
|
function IsError(AnError: TFpError): Boolean; inline;
|
|
function ErrorCode(AnError: TFpError): TFpErrorCode; inline;
|
|
function NoError: TFpError; inline;
|
|
function CreateError(AnErrorCode: TFpErrorCode): TFpError; inline;
|
|
function CreateError(AnErrorCode: TFpErrorCode; AData: array of const): TFpError; inline;
|
|
function CreateError(AnErrorCode: TFpErrorCode; AnError: TFpError; AData: array of const): TFpError; inline;
|
|
|
|
function dbgs(AnError: TFpError): string; overload;
|
|
|
|
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 IsError(AnError: TFpError): Boolean;
|
|
begin
|
|
Result := (length(AnError) > 0) and (AnError[0].ErrorCode <> 0);
|
|
end;
|
|
|
|
function ErrorCode(AnError: TFpError): TFpErrorCode;
|
|
begin
|
|
if length(AnError) > 0 then
|
|
Result := AnError[0].ErrorCode
|
|
else
|
|
Result := fpErrNoError; // 0
|
|
end;
|
|
|
|
function NoError: TFpError;
|
|
begin
|
|
Result:= nil;
|
|
end;
|
|
|
|
function CreateError(AnErrorCode: TFpErrorCode): TFpError;
|
|
begin
|
|
Result := ErrorHandler.CreateError(AnErrorCode, []);
|
|
end;
|
|
|
|
function CreateError(AnErrorCode: TFpErrorCode; AData: array of const): TFpError;
|
|
begin
|
|
Result := ErrorHandler.CreateError(AnErrorCode, AData);
|
|
end;
|
|
|
|
function CreateError(AnErrorCode: TFpErrorCode; AnError: TFpError;
|
|
AData: array of const): TFpError;
|
|
begin
|
|
Result := ErrorHandler.CreateError(AnErrorCode, AnError, AData);
|
|
end;
|
|
|
|
function dbgs(AnError: TFpError): string;
|
|
begin
|
|
if IsError(AnError) then
|
|
Result := '[['+ GetFpErrorHandler.ErrorAsString(AnError) +']]'
|
|
else
|
|
Result := '[[no err]]';
|
|
end;
|
|
|
|
{ TFpErrorHandler }
|
|
|
|
function TFpErrorHandler.GetErrorRawString(AnErrorCode: TFpErrorCode): string;
|
|
begin
|
|
case AnErrorCode of
|
|
fpErrAnyError: Result := MsgfpErrAnyError;
|
|
fpErrSymbolNotFound: Result := MsgfpErrSymbolNotFound;
|
|
fpErrNoMemberWithName: Result := MsgfpErrNoMemberWithName;
|
|
fpErrorNotAStructure: Result := MsgfpErrorNotAStructure;
|
|
|
|
fpErrPasParserInvalidExpression: Result := MsgfpErrPasParserInvalidExpression;
|
|
fpErrPasParserUnexpectedToken: Result := MsgfpErrPasParserUnexpectedToken;
|
|
fpErrPasParserMissingExprAfterComma: Result := MsgfpErrPasParserMissingExprAfterComma;
|
|
fpErrPasParserMissingIndexExpression: Result := MsgfpErrPasParserMissingIndexExpression;
|
|
fpErrInvalidNumber: Result := MsgfpErrInvalidNumber;
|
|
fpErrCannotDereferenceType: Result := MsgfpErrCannotDereferenceType;
|
|
fpErrTypeHasNoIndex: Result := MsgfpErrTypeHasNoIndex;
|
|
|
|
fpErrCanNotReadInvalidMem: Result := MsgfpErrCanNotReadInvalidMem;
|
|
fpErrCanNotReadMemAtAddr: Result := MsgfpErrCanNotReadMemAtAddr;
|
|
fpErrFailedReadMem: Result := MsgfpErrfpErrFailedReadMem;
|
|
|
|
fpErrLocationParser: Result := MsgfpErrLocationParser;
|
|
fpErrLocationParserMemRead: Result := MsgfpErrLocationParserMemRead;
|
|
fpErrLocationParserInit: Result := MsgfpErrLocationParserInit;
|
|
fpErrLocationParserMinStack: Result := MsgfpErrLocationParserMinStack;
|
|
fpErrLocationParserNoAddressOnStack: Result := MsgfpErrLocationParserNoAddressOnStack;
|
|
end;
|
|
end;
|
|
|
|
function TFpErrorHandler.CreateError(AnErrorCode: TFpErrorCode;
|
|
AData: array of const): TFpError;
|
|
var
|
|
i: Integer;
|
|
begin
|
|
SetLength(Result, 1);
|
|
Result[0].ErrorCode := AnErrorCode;
|
|
SetLength(Result[0].ErrorData, Length(AData));
|
|
SetLength(Result[0].ErrorData2, Length(AData));
|
|
for i := low(AData) to high(AData) do begin
|
|
Result[0].ErrorData[i] := AData[i];
|
|
case AData[i].VType of
|
|
vtExtended : begin
|
|
Result[0].ErrorData2[i].ext := AData[i].VExtended^;
|
|
Result[0].ErrorData[i].VExtended := @Result[0].ErrorData2[i].ext;
|
|
end;
|
|
vtString : begin
|
|
Result[0].ErrorData2[i].short := AData[i].VString^;
|
|
Result[0].ErrorData[i].VString := @Result[0].ErrorData2[i].short;
|
|
end;
|
|
vtAnsiString : begin
|
|
Result[0].ErrorData2[i].ansi := Ansistring(AData[i].VAnsiString);
|
|
Result[0].ErrorData[i].VAnsiString := Pointer(Result[0].ErrorData2[i].ansi);
|
|
end;
|
|
vtCurrency : begin
|
|
Result[0].ErrorData2[i].cur := AData[i].VCurrency^;
|
|
Result[0].ErrorData[i].VCurrency := @Result[0].ErrorData2[i].cur;
|
|
end;
|
|
vtVariant : begin
|
|
Result[0].ErrorData2[i].vari := AData[i].VVariant^;
|
|
Result[0].ErrorData[i].VVariant := @Result[0].ErrorData2[i].vari;
|
|
end;
|
|
vtWideString : begin
|
|
Result[0].ErrorData2[i].wide := WideString(AData[i].VWideString);
|
|
Result[0].ErrorData[i].VWideString := Pointer(Result[0].ErrorData2[i].wide);
|
|
end;
|
|
vtInt64 : begin
|
|
Result[0].ErrorData2[i].i64 := AData[i].VInt64^;
|
|
Result[0].ErrorData[i].VInt64 := @Result[0].ErrorData2[i].i64;
|
|
end;
|
|
vtUnicodeString : begin
|
|
Result[0].ErrorData2[i].uni := unicodestring(AData[i].VUnicodeString);
|
|
Result[0].ErrorData[i].VUnicodeString := pointer(Result[0].ErrorData2[i].uni);
|
|
end;
|
|
vtQWord : begin
|
|
Result[0].ErrorData2[i].qw := AData[i].VQWord^;
|
|
Result[0].ErrorData[i].VQWord := @Result[0].ErrorData2[i].qw;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TFpErrorHandler.CreateError(AnErrorCode: TFpErrorCode; AnError: TFpError;
|
|
AData: array of const): TFpError;
|
|
var
|
|
i: Integer;
|
|
begin
|
|
Result := CreateError(AnErrorCode, AData);
|
|
SetLength(Result, Length(AnError) + 1);
|
|
for i := 0 to Length(AnError) - 1 do
|
|
Result[i+1] := AnError[i];
|
|
end;
|
|
|
|
function TFpErrorHandler.ErrorAsString(AnError: TFpError): string;
|
|
var
|
|
RealData: Array of TVarRec;
|
|
i, l: Integer;
|
|
s: String;
|
|
begin
|
|
i := Length(AnError) - 1;
|
|
Result := '';
|
|
while i >= 0 do begin
|
|
RealData := AnError[i].ErrorData;
|
|
l := Length(RealData);
|
|
SetLength(RealData, l + 1);
|
|
s := Result;
|
|
UniqueString(s);
|
|
RealData[l].VAnsiString := pointer(s);
|
|
RealData[l].VType := vtAnsiString;
|
|
// to do : Errorcode may be mapped, if required by outer error
|
|
Result := ErrorAsString(AnError[i].ErrorCode, RealData);
|
|
dec(i);
|
|
end;
|
|
end;
|
|
|
|
function TFpErrorHandler.ErrorAsString(AnErrorCode: TFpErrorCode;
|
|
AData: array of const): string;
|
|
var
|
|
RealData: Array of TVarRec;
|
|
i: Integer;
|
|
s: String;
|
|
begin
|
|
Result := '';
|
|
if AnErrorCode = fpErrNoError then exit;
|
|
SetLength(RealData, Length(AData) + 1);
|
|
s := LineEnding;
|
|
RealData[0].VAnsiString := Pointer(s); // first arg is always line end
|
|
RealData[0].VType := vtAnsiString;
|
|
for i := 0 to Length(AData) - 1 do
|
|
RealData[i + 1] := AData[i];
|
|
s := GetErrorRawString(AnErrorCode);
|
|
if s = '' then s := 'Internal Error: ' + IntToStr(AnErrorCode);
|
|
try
|
|
Result := Format(s, RealData);
|
|
except
|
|
Result := 'Internal Error(2): ' + IntToStr(AnErrorCode);
|
|
end;
|
|
end;
|
|
|
|
finalization
|
|
FreeAndNil(TheErrorHandler);
|
|
|
|
end.
|
|
|