debugger: disassembler, Allow copy to clipboard

git-svn-id: trunk@28238 -
This commit is contained in:
martin 2010-11-15 02:09:28 +00:00
parent 4bcf14762c
commit 624c9a9db4
2 changed files with 195 additions and 82 deletions

View File

@ -18,7 +18,10 @@ inherited AssemblerDlg: TAssemblerDlg
Height = 272 Height = 272
Top = 0 Top = 0
Width = 376 Width = 376
PopupMenu = PopupMenu1
OnMouseDown = pbAsmMouseDown OnMouseDown = pbAsmMouseDown
OnMouseMove = pbAsmMouseMove
OnMouseUp = pbAsmMouseUp
OnMouseWheel = pbAsmMouseWheel OnMouseWheel = pbAsmMouseWheel
OnPaint = pbAsmPaint OnPaint = pbAsmPaint
end end
@ -46,4 +49,12 @@ inherited AssemblerDlg: TAssemblerDlg
OnChange = sbVerticalChange OnChange = sbVerticalChange
OnScroll = sbVerticalScroll OnScroll = sbVerticalScroll
end end
object PopupMenu1: TPopupMenu[3]
left = 493
top = 43
object CopyToClipboard: TMenuItem
Caption = 'New Item1'
OnClick = CopyToClipboardClick
end
end
end end

View File

@ -7,7 +7,7 @@ interface
uses uses
Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs,
ComCtrls, StdCtrls, Grids, ExtCtrls, LclType, LCLIntf, DebuggerDlg, Debugger, ComCtrls, StdCtrls, Grids, ExtCtrls, LclType, LCLIntf, DebuggerDlg, Debugger,
EditorOptions, Maps, Math, LCLProc; EditorOptions, Maps, Math, LCLProc, Menus, Clipbrd;
type type
@ -21,13 +21,29 @@ type
lmsFuncName // Name of function lmsFuncName // Name of function
); );
TAsmDlgLineEntry = record
State: TAsmDlgLineMapState;
Addr: TDbgPtr;
Dump: String;
Statement: String;
FileName: String;
SourceLine: Integer;
end;
TAsmDlgLineEntries = Array of TAsmDlgLineEntry;
TAssemblerDlg = class(TDebuggerDlg) TAssemblerDlg = class(TDebuggerDlg)
CopyToClipboard: TMenuItem;
pbAsm: TPaintBox; pbAsm: TPaintBox;
PopupMenu1: TPopupMenu;
sbHorizontal: TScrollBar; sbHorizontal: TScrollBar;
sbVertical: TScrollBar; sbVertical: TScrollBar;
procedure CopyToClipboardClick(Sender: TObject);
procedure FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); procedure FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
procedure FormResize(Sender: TObject); procedure FormResize(Sender: TObject);
procedure pbAsmMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); procedure pbAsmMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
procedure pbAsmMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
procedure pbAsmMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X,
Y: Integer);
procedure pbAsmMouseWheel(Sender: TObject; Shift: TShiftState; WheelDelta: Integer; MousePos: TPoint; var Handled: Boolean); procedure pbAsmMouseWheel(Sender: TObject; Shift: TShiftState; WheelDelta: Integer; MousePos: TPoint; var Handled: Boolean);
procedure pbAsmPaint(Sender: TObject); procedure pbAsmPaint(Sender: TObject);
procedure sbHorizontalChange(Sender: TObject); procedure sbHorizontalChange(Sender: TObject);
@ -38,6 +54,7 @@ type
FDisassembler: TIDEDisassembler; FDisassembler: TIDEDisassembler;
FDisassemblerNotification: TIDEDisassemblerNotification; FDisassemblerNotification: TIDEDisassemblerNotification;
FLocation: TDBGPtr; FLocation: TDBGPtr;
FMouseIsDown: Boolean;
FTopLine: Integer; FTopLine: Integer;
FLastTopLine: Integer; FLastTopLine: Integer;
@ -46,15 +63,10 @@ type
FLastTopLineValid: Boolean; FLastTopLineValid: Boolean;
FSelectLine: Integer; FSelectLine: Integer;
FSelectionEndLine: Integer;
FLineCount: Integer; FLineCount: Integer;
FLineMap: array of record FLineMap: TAsmDlgLineEntries;
State: TAsmDlgLineMapState;
Addr: TDbgPtr;
Dump: String;
Statement: String;
FileName: String;
SourceLine: Integer;
end;
FLineHeight: Integer; FLineHeight: Integer;
FCharWidth: Integer; FCharWidth: Integer;
FGutterWidth: Integer; FGutterWidth: Integer;
@ -63,8 +75,15 @@ type
procedure ClearLineMap(AState: TAsmDlgLineMapState = lmsUnknown); procedure ClearLineMap(AState: TAsmDlgLineMapState = lmsUnknown);
procedure DisassemblerChanged(Sender: TObject); procedure DisassemblerChanged(Sender: TObject);
procedure SetDisassembler(const AValue: TIDEDisassembler); procedure SetDisassembler(const AValue: TIDEDisassembler);
function FormatLine(ALine: TAsmDlgLineEntry; W: Integer): String;
procedure UpdateLineData; procedure UpdateLineData;
procedure SetSelection(ALine: Integer; AMakeVisible: Boolean); procedure UpdateLineDataEx(ALineMap: TAsmDlgLineEntries;
AFirstLine, ALineCount: Integer;
var ACachedLine, ACachedIdx: Integer;
var ACachedIsSrc, ACachedValid: Boolean;
ACachedUpdate: Boolean
);
procedure SetSelection(ALine: Integer; AMakeVisible: Boolean; AKeepSelEnd: Boolean = False);
procedure SetLineCount(ALineCount: Integer); procedure SetLineCount(ALineCount: Integer);
procedure SetTopLine(ALine: Integer); procedure SetTopLine(ALine: Integer);
protected protected
@ -137,6 +156,7 @@ begin
pbAsm.Font.Height := EditorOpts.EditorFontHeight; pbAsm.Font.Height := EditorOpts.EditorFontHeight;
pbAsm.Font.Name := EditorOpts.EditorFont; pbAsm.Font.Name := EditorOpts.EditorFont;
Caption := lisMenuViewAssembler; Caption := lisMenuViewAssembler;
CopyToClipboard.Caption := lisDbgAsmCopyToClipboard;
end; end;
destructor TAssemblerDlg.Destroy; destructor TAssemblerDlg.Destroy;
@ -148,32 +168,58 @@ begin
end; end;
procedure TAssemblerDlg.FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); procedure TAssemblerDlg.FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
var
i: LongInt;
begin begin
if Shift <> [] then Exit; if Shift - [ssShift] <> [] then Exit;
case Key of case Key of
VK_UP: begin VK_UP: begin
SetSelection(FSelectLine - 1, True); SetSelection(FSelectLine - 1, True, ssShift in Shift);
Exit;
end; end;
VK_DOWN: begin VK_DOWN: begin
SetSelection(FSelectLine + 1, True); SetSelection(FSelectLine + 1, True, ssShift in Shift);
Exit;
end; end;
VK_PRIOR: begin VK_PRIOR: begin
Dec(FSelectLine, FLineCount); i := FTopLine;
SetTopline(FTopLine - FLineCount); SetSelection(FSelectLine - FLineCount, False, ssShift in Shift);
SetTopline(i - FLineCount);
end; end;
VK_NEXT: begin VK_NEXT: begin
Inc(FSelectLine, FLineCount); i := FTopLine;
SetTopline(FTopLine + FLineCount); SetSelection(FSelectLine + FLineCount, False, ssShift in Shift);
SetTopline(i + FLineCount);
end; end;
VK_LEFT: sbHorizontal.Position := sbHorizontal.Position - sbHorizontal.SmallChange; VK_LEFT: sbHorizontal.Position := sbHorizontal.Position - sbHorizontal.SmallChange;
VK_RIGHT: sbHorizontal.Position := sbHorizontal.Position + sbHorizontal.SmallChange; VK_RIGHT: sbHorizontal.Position := sbHorizontal.Position + sbHorizontal.SmallChange;
VK_HOME: sbHorizontal.Position := 0; VK_HOME: sbHorizontal.Position := 0;
end; end;
Key := 0;
pbAsm.Invalidate; pbAsm.Invalidate;
end; end;
procedure TAssemblerDlg.CopyToClipboardClick(Sender: TObject);
var
ALineMap: TAsmDlgLineEntries;
i, w: Integer;
s: String;
begin
if FSelectionEndLine = FSelectLine
then exit;
SetLength(ALineMap, abs(FSelectionEndLine - FSelectLine)+1);
UpdateLineDataEx(ALineMap, Min(FSelectionEndLine, FSelectLine),
abs(FSelectionEndLine - FSelectLine),
FLastTopLine, FLastTopLineIdx, FLastTopLineIsSrc, FLastTopLineValid, False );
if FDebugger = nil
then W := 16
else W := FDebugger.TargetWidth div 4;
s := '';
for i := 0 to length(ALineMap)-1 do
begin
s := s + FormatLine(ALineMap[i], W) + LineEnding;
end;
Clipboard.AsText := s;
end;
procedure TAssemblerDlg.DisassemblerChanged(Sender: TObject); procedure TAssemblerDlg.DisassemblerChanged(Sender: TObject);
begin begin
if (FDisassembler = nil) or (FLocation = 0) or (FLineCount = 0) if (FDisassembler = nil) or (FLocation = 0) or (FLineCount = 0)
@ -230,14 +276,33 @@ procedure TAssemblerDlg.pbAsmMouseDown(Sender: TObject; Button: TMouseButton; Sh
begin begin
if Button <> mbLeft then exit; if Button <> mbLeft then exit;
SetSelection(FTopLine + Y div FLineHeight, True); SetSelection(FTopLine + Y div FLineHeight, False, ssShift in Shift);
FMouseIsDown := True;
end;
procedure TAssemblerDlg.pbAsmMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
begin
y := Y div FLineHeight;
if FMouseIsDown and (y >= 0) and (y < FLineCount)
then SetSelection(FTopLine + Y, False, True);
end;
procedure TAssemblerDlg.pbAsmMouseUp(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
FMouseIsDown := False;
end; end;
procedure TAssemblerDlg.pbAsmMouseWheel(Sender: TObject; Shift: TShiftState; WheelDelta: Integer; MousePos: TPoint; var Handled: Boolean); procedure TAssemblerDlg.pbAsmMouseWheel(Sender: TObject; Shift: TShiftState; WheelDelta: Integer; MousePos: TPoint; var Handled: Boolean);
var
i, j: LongInt;
begin begin
Handled := True; Handled := True;
SetSelection(FSelectLine - (WheelDelta div 120), True); j := WheelDelta div 120;
i := FTopLine ;
SetSelection(FSelectLine - j, False, ssShift in Shift);
SetTopline(i - j);
end; end;
procedure TAssemblerDlg.pbAsmPaint(Sender: TObject); procedure TAssemblerDlg.pbAsmPaint(Sender: TObject);
@ -263,6 +328,22 @@ begin
for n := 0 to FLineCount do for n := 0 to FLineCount do
begin begin
if Line = FSelectLine if Line = FSelectLine
then begin
pbAsm.Canvas.Brush.Color := clHighlight;
pbAsm.Canvas.Font.Color := clHighlightText;
pbAsm.Canvas.FillRect(R.Left, n * FLineHeight, R.Right, (n + 1) * FLineHeight);
if (FSelectionEndLine <> FSelectLine)
then begin
pbAsm.Canvas.Brush.Color := clHotLight;
pbAsm.Canvas.Brush.Style := bsClear;
pbAsm.Canvas.Rectangle(R.Left, n * FLineHeight, R.Right, (n + 1) * FLineHeight);
pbAsm.Canvas.Brush.Style := bsSolid;
pbAsm.Canvas.Brush.Color := clHighlight;
end;
end
else if (FSelectionEndLine <> FSelectLine)
and (line >= Min(FSelectLine, FSelectionEndLine))
and (line <= Max(FSelectLine, FSelectionEndLine))
then begin then begin
pbAsm.Canvas.Brush.Color := clHighlight; pbAsm.Canvas.Brush.Color := clHighlight;
pbAsm.Canvas.Font.Color := clHighlightText; pbAsm.Canvas.Font.Color := clHighlightText;
@ -274,21 +355,7 @@ begin
end; end;
pbAsm.Canvas.Font.Bold := (FLineMap[n].State in [lmsSource, lmsFuncName]); pbAsm.Canvas.Font.Bold := (FLineMap[n].State in [lmsSource, lmsFuncName]);
S := ''; S := FormatLine(FLineMap[n], W);
//S := Format('[a:%8.8u l:%8.8d i:%3.3u] ', [Cardinal(FLineMap[n].Addr), Line, n]);
S := S + HexStr(FLineMap[n].Addr, W) + ' ';
case FLineMap[n].State of
lmsUnknown: S := S + '??????';
lmsInvalid: S := S + '......';
lmsStatement: S := S + Copy(FLineMap[n].Dump + ' ', 1, 24) + ' ' + FLineMap[n].Statement;
lmsSource: begin
if FLineMap[n].SourceLine = 0
then S := '---'
else S := Format('%s:%u %s', [FLineMap[n].FileName, FLineMap[n].SourceLine, FLineMap[n].Statement]);
end;
lmsFuncName: s:= FLineMap[n].FileName + ' ' + FLineMap[n].Statement;
end;
pbAsm.Canvas.TextRect(R, X, Y, S); pbAsm.Canvas.TextRect(R, X, Y, S);
Inc(Y, FLineHeight); Inc(Y, FLineHeight);
@ -296,6 +363,25 @@ begin
end; end;
end; end;
function TAssemblerDlg.FormatLine(ALine: TAsmDlgLineEntry; W: Integer) : String;
begin
Result := '';
//Result := Format('[a:%8.8u l:%8.8d i:%3.3u] ', [Cardinal(ALine.Addr), Line, n]);
Result := Result + HexStr(ALine.Addr, W) + ' ';
case ALine.State of
lmsUnknown: Result := Result + '??????';
lmsInvalid: Result := Result + '......';
lmsStatement: Result := Result + Copy(ALine.Dump + ' ', 1, 24) + ' ' + ALine.Statement;
lmsSource: begin
if ALine.SourceLine = 0
then Result := '---'
else Result := Format('%s:%u %s', [ALine.FileName, ALine.SourceLine, ALine.Statement]);
end;
lmsFuncName: Result:= ALine.FileName + ' ' + ALine.Statement;
end;
end;
procedure TAssemblerDlg.sbHorizontalChange(Sender: TObject); procedure TAssemblerDlg.sbHorizontalChange(Sender: TObject);
begin begin
pbAsm.Invalidate; pbAsm.Invalidate;
@ -347,7 +433,9 @@ begin
FDebugger := ADebugger; FDebugger := ADebugger;
FTopLine := -(FLineCount div 2); FTopLine := -(FLineCount div 2);
FSelectLine := 0; FSelectLine := 0;
FSelectionEndLine := 0;
FLocation := AAddr; FLocation := AAddr;
FLastTopLineValid := False;
if Visible then begin if Visible then begin
// otherwhise in resize // otherwhise in resize
@ -359,7 +447,8 @@ begin
ClearLineMap; ClearLineMap;
end; end;
procedure TAssemblerDlg.SetSelection(ALine: Integer; AMakeVisible: Boolean); procedure TAssemblerDlg.SetSelection(ALine: Integer; AMakeVisible: Boolean;
AKeepSelEnd: Boolean = False);
var var
OldLine: Integer; OldLine: Integer;
begin begin
@ -369,7 +458,9 @@ begin
// set variable first // set variable first
OldLine := FSelectLine; OldLine := FSelectLine;
FSelectLine := Aline; FSelectLine := Aline;
FLastTopLineValid := False;
if not AKeepSelEnd
then FSelectionEndLine := FSelectLine;
if AMakeVisible if AMakeVisible
then begin then begin
@ -421,6 +512,14 @@ end;
procedure TAssemblerDlg.UpdateLineData; procedure TAssemblerDlg.UpdateLineData;
begin
UpdateLineDataEx(FLineMap, FTopLine, FLineCount,
FLastTopLine, FLastTopLineIdx, FLastTopLineIsSrc, FLastTopLineValid, True);
end;
procedure TAssemblerDlg.UpdateLineDataEx(ALineMap: TAsmDlgLineEntries; AFirstLine,
ALineCount: Integer; var ACachedLine, ACachedIdx: Integer;
var ACachedIsSrc, ACachedValid: Boolean; ACachedUpdate: Boolean);
function GetItem(AIdx: Integer): PDisassemblerEntry; function GetItem(AIdx: Integer): PDisassemblerEntry;
begin begin
@ -477,8 +576,8 @@ begin
try try
FUpdateNeeded := False; FUpdateNeeded := False;
DoneLocation := FLocation; DoneLocation := FLocation;
DoneTopLine := FTopLine; DoneTopLine := AFirstLine;
DoneLineCount := FLineCount; DoneLineCount := ALineCount;
DoneCountBefore := FDisassembler.CountBefore; DoneCountBefore := FDisassembler.CountBefore;
DoneCountAfter := FDisassembler.CountAfter; DoneCountAfter := FDisassembler.CountAfter;
@ -486,15 +585,15 @@ begin
Line := 0; Line := 0;
Idx := 0; Idx := 0;
LineIsSrc := False; LineIsSrc := False;
if FLastTopLineValid if ACachedValid
and (abs(FTopLine - FLastTopLine) < FTopLine) and (abs(AFirstLine - ACachedLine) < AFirstLine)
then begin then begin
Line := FLastTopLine; Line := ACachedLine;
Idx := FLastTopLineIdx; Idx := ACachedIdx;
LineIsSrc := FLastTopLineIsSrc; LineIsSrc := ACachedIsSrc;
end; end;
while FTopLine > Line while AFirstLine > Line
do begin do begin
if LineIsSrc if LineIsSrc
then begin then begin
@ -510,7 +609,7 @@ begin
end; end;
inc(Line); inc(Line);
end; end;
while FTopLine < line while AFirstLine < line
do begin do begin
if LineIsSrc if LineIsSrc
then begin then begin
@ -527,22 +626,25 @@ begin
Dec(Line); Dec(Line);
end; end;
FLastTopLine := FTopLine; if ACachedUpdate
FLastTopLineIdx := Idx; then begin
FLastTopLineIsSrc := LineIsSrc; ACachedLine := AFirstLine;
FLastTopLineValid := True; ACachedIdx := Idx;
ACachedIsSrc := LineIsSrc;
ACachedValid := True;
end;
// Fill LineMap // Fill LineMap
HasLineOutOfRange := False; HasLineOutOfRange := False;
Line := 0; Line := 0;
NextItm := GetItem(Idx); NextItm := GetItem(Idx);
while Line <= FLineCount do begin while Line <= ALineCount do begin
Itm := NextItm; Itm := NextItm;
NextItm := GetItem(Idx+1); NextItm := GetItem(Idx+1);
if Itm = nil if Itm = nil
then begin then begin
FLineMap[Line].State := lmsInvalid; ALineMap[Line].State := lmsInvalid;
HasLineOutOfRange := True; HasLineOutOfRange := True;
inc(Line); inc(Line);
inc(idx); inc(idx);
@ -552,18 +654,18 @@ begin
if ( (Line = 0) and LineIsSrc ) if ( (Line = 0) and LineIsSrc )
or ( (Line <> 0) and IsSourceBeforeItem(Itm) ) or ( (Line <> 0) and IsSourceBeforeItem(Itm) )
then begin then begin
FLineMap[Line].Dump := ''; ALineMap[Line].Dump := '';
FLineMap[Line].Statement := ''; ALineMap[Line].Statement := '';
if Itm^.SrcFileName <> '' if Itm^.SrcFileName <> ''
then begin then begin
FLineMap[Line].State := lmsSource; ALineMap[Line].State := lmsSource;
FLineMap[Line].SourceLine := Itm^.SrcFileLine; ALineMap[Line].SourceLine := Itm^.SrcFileLine;
FLineMap[Line].FileName := Itm^.SrcFileName; ALineMap[Line].FileName := Itm^.SrcFileName;
end end
else begin else begin
FLineMap[Line].State := lmsFuncName; ALineMap[Line].State := lmsFuncName;
FLineMap[Line].SourceLine := Itm^.Offset; ALineMap[Line].SourceLine := Itm^.Offset;
FLineMap[Line].FileName := Itm^.FuncName; ALineMap[Line].FileName := Itm^.FuncName;
end; end;
inc(Line); inc(Line);
end end
@ -573,26 +675,26 @@ begin
or ( (Itm^.SrcFileName = '') and (Itm^.FuncName <> '') and (NextItm <> nil) and (Itm^.Offset < NextItm^.Offset) ) or ( (Itm^.SrcFileName = '') and (Itm^.FuncName <> '') and (NextItm <> nil) and (Itm^.Offset < NextItm^.Offset) )
) )
then begin then begin
FLineMap[Line].Dump := ''; ALineMap[Line].Dump := '';
FLineMap[Line].Statement := ''; ALineMap[Line].Statement := '';
if Itm^.SrcFileName <> '' if Itm^.SrcFileName <> ''
then begin then begin
FLineMap[Line].State := lmsSource; ALineMap[Line].State := lmsSource;
FLineMap[Line].SourceLine := Itm^.SrcFileLine; ALineMap[Line].SourceLine := Itm^.SrcFileLine;
FLineMap[Line].FileName := Itm^.SrcFileName; ALineMap[Line].FileName := Itm^.SrcFileName;
if NextItm <> nil if NextItm <> nil
then FLineMap[Line].Statement := Format('(%d of %d)', [NextItm^.SrcStatementIndex, NextItm^.SrcStatementCount]) then ALineMap[Line].Statement := Format('(%d of %d)', [NextItm^.SrcStatementIndex, NextItm^.SrcStatementCount])
else FLineMap[Line].Statement := Format('(??? of %d)', [Itm^.SrcStatementCount]); else ALineMap[Line].Statement := Format('(??? of %d)', [Itm^.SrcStatementCount]);
end end
else begin else begin
FLineMap[Line].State := lmsFuncName; ALineMap[Line].State := lmsFuncName;
FLineMap[Line].SourceLine := 0; ALineMap[Line].SourceLine := 0;
if NextItm <> nil if NextItm <> nil
then FLineMap[Line].SourceLine := NextItm^.Offset; then ALineMap[Line].SourceLine := NextItm^.Offset;
FLineMap[Line].FileName := Itm^.FuncName; ALineMap[Line].FileName := Itm^.FuncName;
if NextItm <> nil if NextItm <> nil
then FLineMap[Line].Statement := Format('(%d)', [NextItm^.Offset]) then ALineMap[Line].Statement := Format('(%d)', [NextItm^.Offset])
else FLineMap[Line].Statement := '(???)'; else ALineMap[Line].Statement := '(???)';
end; end;
inc(Line); inc(Line);
inc(idx); // displayed source-info, instead of asm (topline substituted) inc(idx); // displayed source-info, instead of asm (topline substituted)
@ -601,14 +703,14 @@ begin
end; end;
LineIsSrc := False; // only for topline LineIsSrc := False; // only for topline
if Line > FLineCount if Line > ALineCount
then break; then break;
FLineMap[Line].Addr := Itm^.Addr; ALineMap[Line].Addr := Itm^.Addr;
FLineMap[Line].State := lmsStatement; ALineMap[Line].State := lmsStatement;
FLineMap[Line].Dump := Itm^.Dump; ALineMap[Line].Dump := Itm^.Dump;
FLineMap[Line].Statement := Itm^.Statement; ALineMap[Line].Statement := Itm^.Statement;
FLineMap[Line].SourceLine := Itm^.SrcFileLine; ALineMap[Line].SourceLine := Itm^.SrcFileLine;
inc(Line); inc(Line);
inc(idx); inc(idx);
@ -618,8 +720,8 @@ begin
FUpdating := False; FUpdating := False;
if FUpdateNeeded if FUpdateNeeded
and ( (DoneLocation <> FLocation) and ( (DoneLocation <> FLocation)
or (DoneTopLine <> FTopLine) or (DoneTopLine <> AFirstLine)
or (DoneLineCount <> FLineCount) or (DoneLineCount <> ALineCount)
or (HasLineOutOfRange or (HasLineOutOfRange
and ( (DoneCountBefore <> FDisassembler.CountBefore) and ( (DoneCountBefore <> FDisassembler.CountBefore)
or (DoneCountAfter <> FDisassembler.CountAfter) ) ) or (DoneCountAfter <> FDisassembler.CountAfter) ) )