FpGDBMIDebug: Allow toggle to gdb results (run menu), to compare values during beta / remove old code in gdb cache/emulation

git-svn-id: trunk@44569 -
This commit is contained in:
martin 2014-03-31 21:49:45 +00:00
parent 160b1232b0
commit 50fe9876d5
4 changed files with 87 additions and 550 deletions

2
.gitattributes vendored
View File

@ -2023,6 +2023,8 @@ components/lazdebuggerfp/test/TestApps/TestWatchesUnitSimple.pas svneol=native#t
components/lazdebuggerfp/test/TestApps/TestWatchesUnitStruct.pas svneol=native#text/pascal components/lazdebuggerfp/test/TestApps/TestWatchesUnitStruct.pas svneol=native#text/pascal
components/lazdebuggerfp/test/TestFpGdbmi.lpi svneol=native#text/pascal components/lazdebuggerfp/test/TestFpGdbmi.lpi svneol=native#text/pascal
components/lazdebuggerfp/test/TestFpGdbmi.lpr svneol=native#text/pascal components/lazdebuggerfp/test/TestFpGdbmi.lpr svneol=native#text/pascal
components/lazdebuggerfp/test/fpclist.txt.sample svneol=native#text/plain
components/lazdebuggerfp/test/gdblist.txt.sample svneol=native#text/plain
components/lazdebuggerfp/test/testwatches.pas svneol=native#text/pascal components/lazdebuggerfp/test/testwatches.pas svneol=native#text/pascal
components/lazdebuggergdbmi/Makefile svneol=native#text/plain components/lazdebuggergdbmi/Makefile svneol=native#text/plain
components/lazdebuggergdbmi/Makefile.compiled svneol=native#text/plain components/lazdebuggergdbmi/Makefile.compiled svneol=native#text/plain

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, LCLProc, Forms, FpDbgLoader, FpDbgDwarf, LazLoggerBase, GDBTypeInfo, LCLProc, Forms, FpDbgLoader, FpDbgDwarf, LazLoggerBase,
LazLoggerProfiling, LazClasses, FpPascalParser, FpPascalBuilder, FpErrorMessages; LazLoggerProfiling, LazClasses, FpPascalParser, FpPascalBuilder, FpErrorMessages, MenuIntf;
type type
@ -53,18 +53,6 @@ type
procedure CloseProcess; procedure CloseProcess;
end; end;
{ TFpGDBPTypeRequestCache }
TFpGDBPTypeRequestCache = class(TGDBPTypeRequestCache)
private
FDebugger: TFpGDBMIDebugger;
FInIndexOf: Boolean;
public
constructor Create(ADebugger: TFpGDBMIDebugger);
function IndexOf(AThreadId, AStackFrame: Integer; ARequest: TGDBPTypeRequest): Integer; override;
property Debugger: TFpGDBMIDebugger read FDebugger;
end;
const const
MAX_CTX_CACHE = 10; MAX_CTX_CACHE = 10;
@ -96,7 +84,6 @@ type
procedure GetCurrentContext(out AThreadId, AStackFrame: Integer); procedure GetCurrentContext(out AThreadId, AStackFrame: Integer);
function GetLocationForContext(AThreadId, AStackFrame: Integer): TDBGPtr; function GetLocationForContext(AThreadId, AStackFrame: Integer): TDBGPtr;
function GetInfoContextForContext(AThreadId, AStackFrame: Integer): TDbgInfoAddressContext; function GetInfoContextForContext(AThreadId, AStackFrame: Integer): TDbgInfoAddressContext;
function CreateTypeRequestCache: TGDBPTypeRequestCache; override;
property CurrentCommand; property CurrentCommand;
property TargetPID; property TargetPID;
protected protected
@ -181,6 +168,25 @@ type
procedure Cancel(const ASource: String); override; procedure Cancel(const ASource: String); override;
end; end;
var
MenuCmd: TIDEMenuCommand;
CurrentDebugger: TFpGDBMIDebugger;
UseGDB: Boolean;
procedure IDEMenuClicked(Sender: TObject);
begin
UseGDB := (MenuCmd.MenuItem <> nil) and MenuCmd.MenuItem.Checked;
CurrentDebugger.Watches.CurrentWatches.ClearValues;
end;
// This Accessor hack is temporarilly needed / the final version will not show gdb data
type TWatchValueHack = class(TWatchValue) end;
procedure MarkWatchValueAsGdb(AWatchValue: TWatchValue);
begin
AWatchValue.Value := '{GDB:}' + AWatchValue.Value;
TWatchValueHack(AWatchValue).DoDataValidityChanged(ddsRequested);
end;
{ TFpGDBMIDebuggerCommandEvaluate } { TFpGDBMIDebuggerCommandEvaluate }
function TFpGDBMIDebuggerCommandEvaluate.DoExecute: Boolean; function TFpGDBMIDebuggerCommandEvaluate.DoExecute: Boolean;
@ -384,531 +390,6 @@ begin
{$ENDIF} {$ENDIF}
end; end;
{ TFpGDBPTypeRequestCache }
constructor TFpGDBPTypeRequestCache.Create(ADebugger: TFpGDBMIDebugger);
begin
FDebugger := ADebugger;
FInIndexOf := False;
inherited Create;
end;
function TFpGDBPTypeRequestCache.IndexOf(AThreadId, AStackFrame: Integer;
ARequest: TGDBPTypeRequest): Integer;
const
GdbCmdPType = 'ptype ';
GdbCmdWhatIs = 'whatis ';
GdbCmdEval = '-data-evaluate-expression ';
procedure AddType(ASourceExpr: string; ATypeIdent: TFpDbgSymbol; AVal: TFpDbgValue = nil); forward;
procedure FindPointerAndBaseType(ASrcType: TFpDbgSymbol;
out APointerLevel: Integer; out ADeRefType, ABaseType: TFpDbgSymbol;
out ASrcTypeName, ADeRefTypeName, ABaseTypeName: String);
begin
APointerLevel := 0;
ADeRefType := nil;
ABaseType := ASrcType;
ASrcTypeName := ASrcType.Name;
ADeRefTypeName := '';
ABaseTypeName := ABaseType.Name;
while (ABaseType.Kind = skPointer) and (ABaseType.TypeInfo <> nil) do begin
ABaseType := ABaseType.TypeInfo;
inc(APointerLevel);
if ABaseType.Name <> '' then
begin
if ASrcTypeName = '' then
ASrcTypeName := '^' + ABaseType.Name;
if ADeRefTypeName = '' then begin
if APointerLevel = 1
then ADeRefTypeName := ABaseType.Name
else ADeRefTypeName := '^'+ ABaseType.Name;
end
end;
end;
ABaseTypeName := ABaseType.Name;
end;
Function MembersAsGdbText(AStructType: TFpDbgSymbol; WithVisibilty: Boolean; out AText: String): Boolean;
var
CurVis: TDbgSymbolMemberVisibility;
procedure AddVisibility(AVis: TDbgSymbolMemberVisibility);
begin
CurVis := AVis;
if not WithVisibilty then
exit;
if AText <> '' then AText := AText + LineEnding;
case AVis of
svPrivate: AText := AText + ' private' + LineEnding;
svProtected: AText := AText + ' protected' + LineEnding;
svPublic: AText := AText + ' public' + LineEnding;
end;
end;
procedure AddMember(AMember: TFpDbgSymbol);
var
ti: TFpDbgSymbol;
s, s2: String;
begin
//todo: functions / virtual / array ...
s2 := '';
if AMember.Kind = skProcedure then begin
if sfVirtual in AMember.Flags then s2 := ' virtual;';
AText := AText + ' procedure ' + AMember.Name + ' ();' + s2 + LineEnding;
exit
end;
ti := AMember.TypeInfo;
if ti = nil then begin
Result := False;
exit;
end;
s := ti.Name;
if s = '' then begin
if not( (AMember.Kind = skSet) or (AMember.Kind = skEnum) or
(AMember.Kind = skArray) or (AMember.Kind = skPointer) or
(AMember.Kind = skRecord)
)
then begin
Result := False;
exit;
end;
if not GetTypeAsDeclaration(s, ti, [tdfSkipClassBody, tdfSkipRecordBody]) then begin
Result := False;
exit;
end
end;
if AMember.Kind = skFunction then begin
if sfVirtual in AMember.Flags then s2 := ' virtual;';
AText := AText + ' function ' + AMember.Name + ' () : '+s+';' + s2 + LineEnding;
end
else
begin
AText := AText + ' ' + AMember.Name + ' : ' + s + ';' + LineEnding;
end;
end;
var
c: Integer;
i: Integer;
m: TFpDbgSymbol;
begin
Result := True;
AText := '';
c := AStructType.MemberCount;
if c = 0 then
exit;
i := 0;
m := AStructType.Member[i];
AddVisibility(m.MemberVisibility);
while true do begin
if m.MemberVisibility <> CurVis then
AddVisibility(m.MemberVisibility);
AddMember(m);
inc(i);
if (i >= c) or (not Result) then break;
m := AStructType.Member[i];
end;
end;
procedure MaybeAdd(AType: TGDBCommandRequestType; AQuery, AAnswer: String);
var
AReq: TGDBPTypeRequest;
begin
AReq.ReqType := AType;
AReq.Request := AQuery;
if inherited IndexOf(AThreadId, AStackFrame, AReq) < 0 then begin
if AType = gcrtPType then
AReq.Result := ParseTypeFromGdb(AAnswer)
else begin
AReq.Result.GdbDescription := AAnswer;
AReq.Result.Kind := ptprkSimple;
end;
Add(AThreadId, AStackFrame, AReq);
debugln(['**** AddToGDBMICache ', AReq.Request, ' T:', AThreadId, ' S:',AStackFrame]);
//debugln(['**** AddToGDBMICache ', AReq.Request, ' T:', AThreadId, ' S:',AStackFrame, ' >>>> ', AAnswer, ' <<<<']);
end;
end;
procedure AddBaseType(ASourceExpr: string; APointerLevel: Integer;
ASrcTypeName, ADeRefTypeName, ABaseTypeName: String;
ASrcType, ABaseType: TFpDbgSymbol);
var
s, s2, RefToken: String;
begin
if sfSubRange in ABaseType.Flags then begin
GetTypeAsDeclaration(s, ABaseType);
if APointerLevel > 0
then RefToken := '^'
else RefToken := '';
s2 := ASrcType.Name;
if s2 = '' then s2 := s;
MaybeAdd(gcrtPType, GdbCmdPType + ASourceExpr, Format('type = %s%s', [RefToken, s]));
MaybeAdd(gcrtPType, GdbCmdWhatIs + ASourceExpr, Format('type = %s%s', [RefToken, s2]));
if APointerLevel > 0 then begin
if APointerLevel > 1
then RefToken := '^'
else RefToken := '';
if (ADeRefTypeName = '') or (ADeRefTypeName[1] = '^') then
ADeRefTypeName := RefToken + s;
ASourceExpr := GDBMIMaybeApplyBracketsToExpr(ASourceExpr)+'^';
MaybeAdd(gcrtPType, GdbCmdPType + ASourceExpr, Format('type = %s%s', [RefToken, s]));
MaybeAdd(gcrtPType, GdbCmdWhatIs + ASourceExpr, Format('type = %s%s', [ADeRefTypeName]));
end;
exit; // subrange
end;
if APointerLevel > 0 then begin
MaybeAdd(gcrtPType, GdbCmdPType + ASourceExpr, Format('type = ^%s', [ABaseTypeName]));
MaybeAdd(gcrtPType, GdbCmdWhatIs + ASourceExpr, Format('type = %s', [ASrcTypeName]));
ASourceExpr := GDBMIMaybeApplyBracketsToExpr(ASourceExpr);
if APointerLevel > 1 then begin
MaybeAdd(gcrtPType, GdbCmdPType + ASourceExpr + '^', Format('type = ^%s', [ABaseTypeName]));
MaybeAdd(gcrtPType, GdbCmdWhatIs + ASourceExpr + '^', Format('type = %s', [ADeRefTypeName]));
end
else begin
MaybeAdd(gcrtPType, GdbCmdPType + ASourceExpr + '^', Format('type = %s', [ABaseTypeName]));
MaybeAdd(gcrtPType, GdbCmdWhatIs + ASourceExpr + '^', Format('type = %s', [ABaseTypeName]));
end;
end
else begin
MaybeAdd(gcrtPType, GdbCmdPType + ASourceExpr, Format('type = %s', [ABaseTypeName]));
MaybeAdd(gcrtPType, GdbCmdWhatIs + ASourceExpr, Format('type = %s', [ABaseTypeName]));
end;
end;
procedure AddClassType(ASourceExpr: string; APointerLevel: Integer;
ASrcTypeName, ADeRefTypeName, ABaseTypeName: String;
ASrcType, ABaseType: TFpDbgSymbol);
var
s, ParentName, RefToken: String;
s2: String;
begin
if APointerLevel = 0 then
ADeRefTypeName := ASrcTypeName;
if not MembersAsGdbText(ABaseType, True, s2) then
exit;
if (ABaseType.TypeInfo <> nil) then begin
ParentName := ABaseType.TypeInfo.Name;
if ParentName <> '' then
ParentName := ' public ' + ParentName;
end
else
ParentName := '';
s := Format('type = ^%s = class :%s %s%send%s', [ABaseTypeName, ParentName, LineEnding, s2, LineEnding]);
MaybeAdd(gcrtPType, GdbCmdPType + ASourceExpr, s);
s := Format('type = %s%s', [ASrcTypeName, LineEnding]);
MaybeAdd(gcrtPType, GdbCmdWhatIs + ASourceExpr, s);
ASourceExpr := GDBMIMaybeApplyBracketsToExpr(ASourceExpr)+'^';
if APointerLevel > 0
then RefToken := '^'
else RefToken := '';
s := Format('type = %s%s = class :%s %s%send%s', [RefToken, ABaseTypeName, ParentName, LineEnding, s2, LineEnding]);
MaybeAdd(gcrtPType, GdbCmdPType + ASourceExpr, s);
s := Format('type = %s%s', [ADeRefTypeName, LineEnding]);
MaybeAdd(gcrtPType, GdbCmdWhatIs + ASourceExpr, s);
end;
procedure AddRecordType(ASourceExpr: string; APointerLevel: Integer;
ASrcTypeName, ADeRefTypeName, ABaseTypeName: String;
ASrcType, ABaseType: TFpDbgSymbol);
var
s, RefToken: String;
s2: String;
begin
if not MembersAsGdbText(ABaseType, False, s2) then
exit;
if APointerLevel > 0
then RefToken := '^'
else RefToken := '';
s := Format('type = %s%s = record %s%send%s', [RefToken, ABaseTypeName, LineEnding, s2, LineEnding]);
MaybeAdd(gcrtPType, GdbCmdPType + ASourceExpr, s);
if APointerLevel > 0 then begin
s := Format('type = %s%s', [ASrcTypeName, LineEnding]);
MaybeAdd(gcrtPType, GdbCmdWhatIs + ASourceExpr, s);
end;
end;
procedure AddEnumType(ASourceExpr: string; APointerLevel: Integer;
ASrcTypeName, ADeRefTypeName, ABaseTypeName: String;
ASrcType, ABaseType: TFpDbgSymbol);
var
s, s2, RefToken: String;
begin
if APointerLevel > 0
then RefToken := '^'
else RefToken := '';
if GetTypeAsDeclaration(s2, ABaseType) then begin
s := Format('type = %s%s = %s%s', [RefToken, ABaseTypeName, s2, LineEnding]);
MaybeAdd(gcrtPType, GdbCmdPType + ASourceExpr, s);
if APointerLevel > 0 then
MaybeAdd(gcrtPType, GdbCmdWhatIs + ASourceExpr, 'type = ' + ASrcTypeName);
end;
end;
procedure AddSetType(ASourceExpr: string; APointerLevel: Integer;
ASrcTypeName, ADeRefTypeName, ABaseTypeName: String;
ASrcType, ABaseType: TFpDbgSymbol);
var
s, s2, RefToken: String;
begin
case APointerLevel of
0: RefToken := '';
1: RefToken := '^';
else RefToken := '^^';
end;
if GetTypeAsDeclaration(s2, ABaseType) then begin
s := Format('type = %s%s%s', [RefToken, s2, LineEnding]);
MaybeAdd(gcrtPType, GdbCmdPType + ASourceExpr, s);
if ASrcTypeName <> ''
then MaybeAdd(gcrtPType, GdbCmdWhatIs + ASourceExpr, 'type = ' + ASrcTypeName)
else MaybeAdd(gcrtPType, GdbCmdWhatIs + ASourceExpr, s);
end;
end;
procedure AddArrayType(ASourceExpr: string; APointerLevel: Integer;
ASrcTypeName, ADeRefTypeName, ABaseTypeName: String;
ASrcType, ABaseType: TFpDbgSymbol);
var
s: String;
ElemPointerLevel: Integer;
ElemDeRefType, ElemBaseType: TFpDbgSymbol;
ElemSrcTypeName, ElemDeRefTypeName, ElemBaseTypeName: String;
begin
if sfDynArray in ABaseType.Flags then begin
// dyn
if ABaseType.TypeInfo = nil then exit;
FindPointerAndBaseType(ABaseType.TypeInfo, ElemPointerLevel,
ElemDeRefType, ElemBaseType,
ElemSrcTypeName, ElemDeRefTypeName, ElemBaseTypeName);
s := ElemSrcTypeName;
if (s = '') then begin
if not GetTypeAsDeclaration(s, ABaseType.TypeInfo, [tdfDynArrayWithPointer]) then
exit;
s := Format('type = %s%s', [StringOfChar('^', APointerLevel), s]);
end
else
s := Format('type = %s%s', ['^', s]); // ElemSrcTypeName already has ^, if it is pointer
MaybeAdd(gcrtPType, GdbCmdPType + ASourceExpr, s + LineEnding);
s := ASrcTypeName;
if (s = '') then begin
if not GetTypeAsDeclaration(s, ASrcType, [tdfDynArrayWithPointer]) then
exit;
s := Format('type = %s%s', [StringOfChar('^', APointerLevel), s]);
end
else
s := Format('type = %s', [s]);
MaybeAdd(gcrtPType, GdbCmdWhatIs + ASourceExpr, s + LineEnding);
// deref
ASourceExpr := GDBMIMaybeApplyBracketsToExpr(ASourceExpr)+'^';
if APointerLevel = 0 then begin
if not GetTypeAsDeclaration(s, ASrcType, [tdfDynArrayWithPointer]) then
exit;
if s[1] = '^' then begin
Delete(s,1,1);
if (s <> '') and (s[1] = '(') and (s[Length(s)] = ')') then begin
Delete(s,Length(s),1);
Delete(s,1,1);
end;
end;
s := Format('type = %s%s', [s, LineEnding]);
MaybeAdd(gcrtPType, GdbCmdPType + ASourceExpr, s);
AddType(ASourceExpr+'[0]', ABaseType.TypeInfo);
end
else begin
s := ElemSrcTypeName;
if (s = '') then begin
if not GetTypeAsDeclaration(s, ABaseType.TypeInfo, [tdfDynArrayWithPointer]) then
exit;
s := Format('type = %s%s', [StringOfChar('^', APointerLevel-1), s]);
end
else
s := Format('type = ^%s', [s]);
MaybeAdd(gcrtPType, GdbCmdPType + ASourceExpr, s + LineEnding);
end;
end
else begin
// stat
if GetTypeAsDeclaration(s, ASrcType, [tdfDynArrayWithPointer]) then begin
s := Format('type = %s%s', [s, LineEnding]);
MaybeAdd(gcrtPType, GdbCmdPType + ASourceExpr, s);
if ASrcTypeName <> ''
then MaybeAdd(gcrtPType, GdbCmdWhatIs + ASourceExpr, 'type = ' + ASrcTypeName)
else MaybeAdd(gcrtPType, GdbCmdWhatIs + ASourceExpr, s);
end;
if APointerLevel = 0 then exit;
ASrcType := ASrcType.TypeInfo;
if GetTypeAsDeclaration(s, ASrcType, [tdfDynArrayWithPointer]) then begin
ASourceExpr := GDBMIMaybeApplyBracketsToExpr(ASourceExpr)+'^';
s := Format('type = %s%s', [s, LineEnding]);
MaybeAdd(gcrtPType, GdbCmdPType + ASourceExpr, s);
if ASrcTypeName <> ''
then MaybeAdd(gcrtPType, GdbCmdWhatIs + ASourceExpr, 'type = ' + ADeRefTypeName)
else MaybeAdd(gcrtPType, GdbCmdWhatIs + ASourceExpr, s);
end;
end;
end;
procedure AddType(ASourceExpr: string; ATypeIdent: TFpDbgSymbol; AVal: TFpDbgValue = nil);
var
SrcTypeName, // The expressions own type name
DeRefTypeName, // one levvel of pointer followed
BaseTypeName: String; // all poiters followed
DeRefType, BaseType: TFpDbgSymbol;
PointerLevel: Integer;
s: String;
i: Integer;
begin
if (ASourceExpr = '') or (ATypeIdent = nil) then exit;
FindPointerAndBaseType(ATypeIdent, PointerLevel,
DeRefType, BaseType,
SrcTypeName, DeRefTypeName, BaseTypeName);
case BaseType.Kind of
skInteger, skCardinal, skBoolean: begin
AddBaseType(ASourceExpr, PointerLevel,
SrcTypeName, DeRefTypeName, BaseTypeName,
ATypeIdent, BaseType);
if (AVal <> nil) and (ATypeIdent.Kind = skInteger) then
MaybeAdd(gcrtEvalExpr, GdbCmdEval + ASourceExpr, Format(',value="%d"', [AVal.AsInteger]))
else
if (AVal <> nil) and (ATypeIdent.Kind = skCardinal) then
MaybeAdd(gcrtEvalExpr, GdbCmdEval + ASourceExpr, Format(',value="%u"', [AVal.AsCardinal]))
else
if (AVal <> nil) and (ATypeIdent.Kind = skBoolean) then
MaybeAdd(gcrtEvalExpr, GdbCmdEval + ASourceExpr, Format(',value="%s"', [dbgs(AVal.AsBool)]))
else
if (AVal <> nil) and (ATypeIdent.Kind = skPointer) then
MaybeAdd(gcrtEvalExpr, GdbCmdEval + ASourceExpr, Format(',value="%u"', [AVal.AsCardinal]))
;
end;
skChar, skFloat:
AddBaseType(ASourceExpr, PointerLevel,
SrcTypeName, DeRefTypeName, BaseTypeName,
ATypeIdent, BaseType);
skClass:
AddClassType(ASourceExpr, PointerLevel,
SrcTypeName, DeRefTypeName, BaseTypeName,
ATypeIdent, BaseType);
skRecord:
AddRecordType(ASourceExpr, PointerLevel,
SrcTypeName, DeRefTypeName, BaseTypeName,
ATypeIdent, BaseType);
skEnum: begin
AddEnumType(ASourceExpr, PointerLevel,
SrcTypeName, DeRefTypeName, BaseTypeName,
ATypeIdent, BaseType);
if (AVal <> nil) and (ATypeIdent.Kind = skEnum) then
if AVal.AsString = ''
then MaybeAdd(gcrtEvalExpr, GdbCmdEval + ASourceExpr, Format(',value="%u"', [AVal.AsCardinal]))
else MaybeAdd(gcrtEvalExpr, GdbCmdEval + ASourceExpr, Format(',value="%s"', [AVal.AsString]));
end;
skSet: begin
AddSetType(ASourceExpr, PointerLevel,
SrcTypeName, DeRefTypeName, BaseTypeName,
ATypeIdent, BaseType);
if (AVal <> nil) and (ATypeIdent.Kind = skSet) then begin
s := '';
for i := 0 to AVal.MemberCount-1 do
if i = 0
then s := AVal.Member[i].AsString
else s := s + ', ' + AVal.Member[i].AsString;
MaybeAdd(gcrtEvalExpr, GdbCmdEval + ASourceExpr, Format(',value="[%s]"', [s]))
end;
end;
skArray:
AddArrayType(ASourceExpr, PointerLevel,
SrcTypeName, DeRefTypeName, BaseTypeName,
ATypeIdent, BaseType);
end;
end;
var
IdentName: String;
PasExpr: TFpPascalExpression;
rt: TFpDbgSymbol;
begin
Result := inherited IndexOf(AThreadId, AStackFrame, ARequest);
DebugLn(['######## '+ARequest.Request, ' ## FOUND: ', dbgs(Result)]);
if (Result >= 0) or FInIndexOf or (not FDebugger.HasDwarf) then
exit;
FDebugger.FMemReader.FThreadId := AThreadId;
FDebugger.FMemReader.FStackFrame := AStackFrame;
FInIndexOf := True;
PasExpr := nil;
try
if (ARequest.ReqType = gcrtPType) and (length(ARequest.Request) > 0) then begin
case ARequest.Request[1] of
'p': if copy(ARequest.Request, 1, 6) = 'ptype ' then
IdentName := trim(copy(ARequest.Request, 7, length(ARequest.Request)));
'w': if copy(ARequest.Request, 1, 7) = 'whatis ' then
IdentName := trim(copy(ARequest.Request, 8, length(ARequest.Request)));
end;
if IdentName <> '' then begin
PasExpr := TFpPascalExpression.Create(IdentName, FDebugger.GetInfoContextForContext(AThreadId, AStackFrame));
rt := nil;
if PasExpr.Valid and (PasExpr.ResultValue <> nil) then begin
rt := PasExpr.ResultValue.DbgSymbol; // value or typecast
if rt <> nil then debugln(['@@@@@ ',rt.ClassName]);
DebugLn(['== VAL === ', PasExpr.ResultValue.AsInteger, ' / ', PasExpr.ResultValue.AsCardinal, ' / ', PasExpr.ResultValue.AsBool, ' / ', PasExpr.ResultValue.AsString, ' / ', PasExpr.ResultValue.MemberCount, ' / ', PasExpr.ResultValue.AsFloat]);
if (rt <> nil) and (rt is TDbgDwarfValueIdentifier) then begin
// symbol is value
rt := rt.TypeInfo;
AddType(IdentName, rt, PasExpr.ResultValue);
Result := inherited IndexOf(AThreadId, AStackFrame, ARequest);
end
else
if rt <> nil then begin
// symbol is type
AddType(IdentName, rt, nil);
Result := inherited IndexOf(AThreadId, AStackFrame, ARequest);
end;
end
else DebugLn(['NOT VALID ', PasExpr.DebugDump(True)])
;
end;
end;
finally
PasExpr.Free;
FInIndexOf := False;
end;
end;
{ TFPGDBMIWatches } { TFPGDBMIWatches }
function TFPGDBMIWatches.FpDebugger: TFpGDBMIDebugger; function TFPGDBMIWatches.FpDebugger: TFpGDBMIDebugger;
@ -942,13 +423,19 @@ begin
try try
WatchValue := TWatchValue(FpDebugger.FWatchEvalList[0]); WatchValue := TWatchValue(FpDebugger.FWatchEvalList[0]);
ResTypeInfo := nil; ResTypeInfo := nil;
if UseGDB then begin
inherited InternalRequestData(WatchValue);
if IsWatchValueAlive then
MarkWatchValueAsGdb(WatchValue);
end
else
if not FpDebugger.EvaluateExpression(WatchValue, WatchValue.Expression, ResText, ResTypeInfo) if not FpDebugger.EvaluateExpression(WatchValue, WatchValue.Expression, ResText, ResTypeInfo)
then begin then begin
if IsWatchValueAlive then debugln(['TFPGDBMIWatches.InternalRequestData FAILED ', WatchValue.Expression]); if IsWatchValueAlive then debugln(['TFPGDBMIWatches.InternalRequestData FAILED ', WatchValue.Expression]);
if IsWatchValueAlive then if IsWatchValueAlive then
inherited InternalRequestData(WatchValue); inherited InternalRequestData(WatchValue);
if IsWatchValueAlive then if IsWatchValueAlive then
WatchValue.Value := '{GDB:}'+WatchValue.Value; MarkWatchValueAsGdb(WatchValue);
end; end;
finally finally
if IsWatchValueAlive then begin if IsWatchValueAlive then begin
@ -1154,14 +641,19 @@ function TFpGDBMIDebugger.RequestCommand(const ACommand: TDBGCommand;
var var
EvalFlags: TDBGEvaluateFlags; EvalFlags: TDBGEvaluateFlags;
begin begin
if HasDwarf and (ACommand = dcEvaluate) then begin if (ACommand = dcEvaluate) then begin
EvalFlags := []; EvalFlags := [];
EvalFlags := TDBGEvaluateFlags(AParams[3].VInteger); EvalFlags := TDBGEvaluateFlags(AParams[3].VInteger);
Result := EvaluateExpression(nil, String(AParams[0].VAnsiString), Result := False;
String(AParams[1].VPointer^), TDBGType(AParams[2].VPointer^), if (HasDwarf) and (not UseGDB) then begin
EvalFlags); Result := EvaluateExpression(nil, String(AParams[0].VAnsiString),
if not Result then String(AParams[1].VPointer^), TDBGType(AParams[2].VPointer^),
EvalFlags);
end;
if not Result then begin
Result := inherited RequestCommand(ACommand, AParams); Result := inherited RequestCommand(ACommand, AParams);
String(AParams[1].VPointer^) := '{GDB:}'+String(AParams[1].VPointer^);
end;
end end
else else
Result := inherited RequestCommand(ACommand, AParams); Result := inherited RequestCommand(ACommand, AParams);
@ -1295,11 +787,6 @@ type
property InformationEntry; property InformationEntry;
end; end;
function TFpGDBMIDebugger.CreateTypeRequestCache: TGDBPTypeRequestCache;
begin
Result := TFpGDBPTypeRequestCache.Create(Self);
end;
procedure TFpGDBMIDebugger.DoWatchFreed(Sender: TObject); procedure TFpGDBMIDebugger.DoWatchFreed(Sender: TObject);
begin begin
FWatchEvalList.Remove(pointer(Sender)); FWatchEvalList.Remove(pointer(Sender));
@ -1597,10 +1084,12 @@ constructor TFpGDBMIDebugger.Create(const AExternalDebugger: String);
begin begin
FWatchEvalList := TList.Create; FWatchEvalList := TList.Create;
inherited Create(AExternalDebugger); inherited Create(AExternalDebugger);
CurrentDebugger := self;
end; end;
destructor TFpGDBMIDebugger.Destroy; destructor TFpGDBMIDebugger.Destroy;
begin begin
CurrentDebugger := nil;
UnLoadDwarf; UnLoadDwarf;
FWatchEvalList.Free; FWatchEvalList.Free;
inherited Destroy; inherited Destroy;
@ -1609,6 +1098,12 @@ end;
procedure Register; procedure Register;
begin begin
RegisterDebugger(TFpGDBMIDebugger); RegisterDebugger(TFpGDBMIDebugger);
MenuCmd := RegisterIDEMenuCommand(itmRunDebugging, 'fpGdbmiToggleGDB', 'Display GDB instead of FpDebug Watches', nil,
@IDEMenuClicked);
MenuCmd.AutoCheck := True;
MenuCmd.Checked := False;
end; end;
end. end.

View File

@ -0,0 +1,21 @@
//This is a sample config for the test
//
//This file contains the list of all fpc that should be tested
//Entries start with a line in [] brackets, giving a name that is
//displayed by the test.
//There must be an entry starting with exe=
//The symbols= line specifies, with which debug info this fpc should be tested.
[fpc 2.6.2]
exe=C:\lazarus\fpc\2.6.2\bin\i386-win32\fpc.exe
symbols=gw,gwset
[fpc 2.6.2 external linker]
exe=C:\lazarus\fpc\2.6.2\bin\i386-win32\fpc.exe
symbols=gw,gwset
opts=-Xe
//[fpc trunk]
//exe=c:\FPC\trunk\bin\i386-win32\fpc.exe
//symbols=gw,gwset

View File

@ -0,0 +1,19 @@
//This is a sample config for the test
//
//This file contains the list of all gdb that should be tested
//Entries start with a line in [] brackets, giving a name that is
//displayed by the test.
//There must be an entry starting with exe=
//The version is specified as one integer, made up from 3 pairs of 2 digits.
//The symbols= line specifies, with which debug info this gdb should be tested.
//[gdb 7.0]
//exe=C:\GDB\7.0\gdb.exe
//version=070000
//symbols=gw,gwset
[gdb 7.2.1 from installer]
exe=C:\lazarus\mingw\i386-win32\bin\gdb.exe
version=070201
symbols=gw,gwset