cheat-engine/Cheat Engine/disassemblerviewlinesunit.pas
2020-01-17 07:50:32 +09:00

1013 lines
28 KiB
ObjectPascal
Executable File

unit disassemblerviewlinesunit;
{$MODE Delphi}
interface
uses LCLIntf,sysutils, classes,ComCtrls, graphics, CEFuncProc, disassembler,
CEDebugger, debughelper, KernelDebugger, symbolhandler, plugin,
disassemblerComments, SymbolListHandler, ProcessHandlerUnit;
type
TDisassemblerViewColorsState=(csUndefined=-1, csNormal=0, csHighlighted=1, csSecondaryHighlighted=2, csBreakpoint=3, csHighlightedbreakpoint=4, csSecondaryHighlightedbreakpoint=5, csUltimap=6, csHighlightedUltimap=7, csSecondaryHighlightedUltimap=8);
TDisassemblerViewColors=array [csNormal..csSecondaryHighlightedUltimap] of record
backgroundcolor: TColor;
normalcolor: TColor;
registercolor: TColor;
symbolcolor: TColor;
hexcolor: TColor;
end;
PDisassemblerViewColors=^TDisassemblerViewColors;
TDisassemblerLine=class
private
fowner: TObject;
fbitmap: tbitmap;
fCanvas: TCanvas;
fHeaders: THeaderSections;
ftop: integer;
fheight: integer; //height of the line
fDefaultHeight: integer; //the normal height without anything extra
fInstructionCenter: integer; //y position of the center of the disassembled line (so no header)
isselected: boolean;
faddress: ptrUint;
fdescription: string;
fdisassembled: string;
fisJump: boolean;
fjumpcolor: TColor;
fJumpsTo: ptrUint;
fcolors: PDisassemblerViewColors;
addressstring: string;
bytestring: string;
opcodestring: string;
specialstring: string;
specialstrings: tstringlist;
customheaderstrings: tstringlist;
parameterstring: string;
referencedbylineheight: integer;
boldheight: integer;
textheight: integer;
refferencedByStart: integer;
isbp,isultimap: boolean;
focused: boolean;
function truncatestring(s: string; maxwidth: integer; hasSpecialChars: boolean=false): string;
procedure buildReferencedByString(sl: tstringlist);
function DrawTextRectWithColor(const ARect: TRect; X, Y: integer; const Text: string): integer;
public
property instructionCenter: integer read fInstructionCenter;
function isJumpOrCall(var addressitjumpsto: ptrUint): boolean;
function getReferencedByAddress(y: integer):ptruint;
function getHeight: integer;
function getTop: integer;
property description:string read fdescription;
property disassembled:string read fdisassembled;
procedure renderLine(var address: ptrUint; linestart: integer; selected: boolean=false; focused: boolean=false; spaceAboveLines:integer=0; spaceBelowLines:integer=0);
procedure drawJumplineTo(yposition: integer; offset: integer; showendtriangle: boolean=true);
procedure handledisassemblerplugins(addressStringPointer: pointer; bytestringpointer: pointer; opcodestringpointer: pointer; specialstringpointer: pointer; textcolor: PColor);
constructor create(owner: TObject; bitmap: TBitmap; headersections: THeaderSections; colors: PDisassemblerViewColors);
destructor destroy; override;
published
property height: integer read fheight;
property top: integer read fTop;
property defaultHeight: integer read fDefaultHeight;
property Address: ptrUint read faddress;
property Owner: TObject read fowner;
end;
implementation
uses
MemoryBrowserFormUnit, dissectCodeThread,debuggertypedefinitions,
dissectcodeunit, disassemblerviewunit, frmUltimap2Unit, frmcodefilterunit,
BreakpointTypeDef, vmxfunctions;
resourcestring
rsUn = '(Unconditional)';
rsCon = '(Conditional)';
rsCall = '(Call)';
rsMemory = '(Code/Data)';
rsInvalidDisassembly = 'Invalid disassembly';
procedure TDisassemblerLine.drawJumplineTo(yposition: integer; offset: integer; showendtriangle: boolean=true);
var
oldpenstyle: Tpenstyle;
oldpenwidth: integer;
oldpencolor, oldbrushcolor: TColor;
jlThickness: integer;
triangleheight: integer;
begin
jlThickness:=TDisassemblerview(owner).jlThickness;
oldpenstyle:=fCanvas.Pen.Style;
oldpenwidth:=fcanvas.pen.Width;
oldpencolor:=fCanvas.Pen.color;
oldbrushcolor:=fCanvas.Brush.color;
fCanvas.Pen.Color:=fjumpcolor;
fCanvas.Pen.Style:=psDot;
fcanvas.Pen.Width:=jlThickness;
fCanvas.PenPos:=point(fHeaders.items[2].Left,instructioncenter);
fCanvas.LineTo(fHeaders.items[2].Left-offset,instructioncenter);
fCanvas.LineTo(fHeaders.items[2].Left-offset,yposition);
fCanvas.LineTo(fHeaders.items[2].Left,yposition);
fCanvas.Pen.Style:=oldpenstyle;
if showendtriangle then
begin
triangleheight:=defaultHeight div 4;
fCanvas.Brush.Style:=bsSolid; //should be the default, but in case something fucked with it (not in the planning, never intended, so even if someone did do it, I'll undo it)
fCanvas.Brush.Color:=fjumpcolor;
fCanvas.Polygon([point(fheaders.items[2].Left-triangleheight,yposition-triangleheight),point(fheaders.items[2].Left,yposition),point(fheaders.items[2].Left-triangleheight,yposition+triangleheight)]);
end;
fCanvas.Brush.Color:=oldbrushcolor;
fCanvas.Pen.Color:=oldpencolor;
end;
function TDisassemblerLine.isJumpOrCall(var addressitjumpsto: ptrUint): boolean;
begin
result:=fisJump;
if result then
addressitjumpsto:=fJumpsTo;
end;
function TDisassemblerLine.getReferencedByAddress(y: integer):ptruint;
//Search the referenced by strings for one with the correct start (if it has one)
var sl: Tstringlist;
p: integer;
a: string;
i: integer;
begin
result:=0;
sl:=TStringList.create;
buildReferencedByString(sl);
if sl.count>0 then
begin
//find the line that matches with this y pos
p:=refferencedByStart-top;
for i:=0 to sl.count-1 do
begin
p:=p+fcanvas.GetTextHeight(sl[i]);
if p>=y then //found it
begin
a:=copy(sl[i], 1, pos('(', sl[i])-1);
result:=StrToQWord('$'+a);
exit;
end;
end;
end;
freeandnil(sl);
end;
function TDisassemblerLine.truncatestring(s: string; maxwidth: integer; hasSpecialChars: boolean=false): string;
var
dotsize: integer;
charindexes: array of integer;
original: string;
i,j: integer;
insidecommand: boolean;
begin
setlength(charindexes,0);
if s='' then exit(s);
original:=s;
insidecommand:=false;
if hasSpecialChars then
begin
setlength(charindexes, length(s)+1); //skipping index 0
j:=1;
for i:=1 to length(original) do
begin
case original[i] of
'{':
begin
insidecommand:=true;
continue
end;
'}':
begin
if insidecommand then
begin
insidecommand:=false;
continue;
end;
end;
end;
if insidecommand then continue;
s[j]:=original[i];
charindexes[j]:=i;
inc(j);
end;
setlength(s,j-1);
end;
if fCanvas.TextWidth(s)>maxwidth then
begin
dotsize:=fCanvas.TextWidth('...');
maxwidth:=maxwidth-dotsize;
if maxwidth<=0 then
begin
result:=''; //it's too small for '...'
exit;
end;
while fCanvas.TextWidth(s)>maxwidth do
s:=copy(s,1,length(s)-1);
if hasSpecialChars then
begin
i:=charindexes[length(s)];
result:=copy(original,1,i)+'{U}...';
end
else
result:=s+'...';
end
else
begin
if hasSpecialChars then
result:=original
else
result:=s; //it fits
end;
end;
procedure TdisassemblerLine.buildReferencedByString(sl: tstringlist);
var addresses: tdissectarray;
i: integer;
begin
setlength(addresses,0);
if (dissectcode<>nil) and (dissectcode.done) then
begin
if dissectcode.CheckAddress(address, addresses) then
begin
for i:=0 to length(addresses)-1 do
begin
case addresses[i].jumptype of
jtUnconditional:
sl.Add(inttohex(addresses[i].address, 8)+utf8toansi(rsUn));
jtConditional:
sl.Add(inttohex(addresses[i].address, 8)+utf8toansi(rsCon));
jtCall:
sl.Add(inttohex(addresses[i].address, 8)+utf8toansi(rsCall));
jtMemory:
sl.Add(inttohex(addresses[i].address, 8)+utf8toansi(rsMemory));
end;
end;
end;
end;
end;
procedure TDisassemblerLine.renderLine(var address: ptrUint; linestart: integer; selected: boolean=false; focused: boolean=false; spaceAboveLines:integer=0; spaceBelowLines:integer=0);
var
baseofsymbol: qword;
symbolname: string;
parameters, locations,result: string;
comment, header: string;
refferencedby: string;
refferencedbylinecount: integer;
refferencedbyheight: integer;
refferencedbystrings: tstringlist;
i,j: integer;
paddressstring: pchar;
pbytestring: pchar;
popcodestring: pchar;
pspecialstring: pchar;
textcolor: TColor;
bp: PBreakpoint;
ExtraLineRenderAbove: TRasterImage;
AboveX, AboveY: Integer;
ExtraLineRenderBelow: TRasterImage;
BelowX, BelowY: Integer;
// z: ptrUint;
found :boolean;
extrasymboldata: TExtraSymbolData;
iscurrentinstruction: boolean;
PA: qword;
BO: integer;
b: byte;
inactive: boolean;
begin
fcanvas.font.style:=[];
iscurrentinstruction:=MemoryBrowser.lastdebugcontext.{$ifdef cpu64}rip{$else}EIP{$endif}=address;
self.focused:=focused;
ftop:=linestart;
faddress:=address;
if assigned(TDisassemblerview(fowner).OnExtraLineRender) then
begin
AboveX:=-1000;
AboveY:=-1000;
ExtraLineRenderAbove:=TDisassemblerview(fOwner).OnExtraLineRender(self, faddress, true, selected, AboveX, AboveY);
BelowX:=-1000;
BelowY:=-1000;
ExtraLineRenderBelow:=TDisassemblerview(fOwner).OnExtraLineRender(self, faddress, false, selected, BelowX, BelowY);
end
else
begin
ExtraLineRenderAbove:=nil;
ExtraLineRenderBelow:=nil;
end;
isselected:=selected;
refferencedbystrings:=nil;
fheight:=0;
baseofsymbol:=0;
//z:=address;
symbolname:=symhandler.getNameFromAddress(address,symhandler.showsymbols,symhandler.showmodules,@baseofsymbol, @found, 8,false);
if (faddress=baseofsymbol) and found then
begin
extrasymboldata:=symhandler.getExtraDataFromSymbolAtAddress(address);
end
else
extrasymboldata:=nil;
if iscurrentinstruction then
visibleDisassembler.context:=@MemoryBrowser.lastdebugcontext
else
visibleDisassembler.context:=nil;
fdisassembled:=visibleDisassembler.disassemble(address,fdescription);
addressstring:=inttohex(visibleDisassembler.LastDisassembleData.address,8);
bytestring:=visibleDisassembler.getLastBytestring;
opcodestring:=visibleDisassembler.LastDisassembleData.prefix+visibleDisassembler.LastDisassembleData.opcode;
//Correction for rendering bug.
if (processhandler.isNetwork=true) and (processhandler.SystemArchitecture=archarm) then
begin
bytestring+=' ';
opcodestring+=' ';
end;
parameterstring:=visibleDisassembler.LastDisassembleData.parameters+' ';
specialstring:=visibleDisassembler.DecodeLastParametersToString;
if iscurrentinstruction and visibleDisassembler.LastDisassembleData.isconditionaljump and visibleDisassembler.LastDisassembleData.willJumpAccordingToContext then
parameterstring:=parameterstring+' ---> ';
//userdefined comments
if dassemblercomments<>nil then
comment:=dassemblercomments.comments[visibleDisassembler.LastDisassembleData.address]
else
comment:='';
if comment<>'' then
begin
try
specialstring:=format(comment,[specialstring]);
except
specialstring:=comment;
end;
end;
//split up into lines
specialstrings.text:=specialstring;
customheaderstrings.text:=dassemblercomments.commentHeader[visibleDisassembler.LastDisassembleData.address];
if symhandler.showsymbols or symhandler.showmodules then
addressString:=symbolname
else
addressString:=truncatestring(addressString, fHeaders.Items[0].Width-2);
bytestring:=truncatestring(bytestring, fHeaders.Items[1].Width-2, true);
//opcodestring:=truncatestring(opcodestring, fHeaders.Items[2].Width-2, true);
//specialstring:=truncatestring(specialstring, fHeaders.Items[3].Width-2);
if boldheight=-1 then
begin
fcanvas.Font.Style:=[fsbold];
boldheight:=fcanvas.TextHeight(fdisassembled)+1;
fcanvas.Font.Style:=[];
end;
fheight:=fheight+boldheight+1;
fDefaultHeight:=fHeight; //the height without anything special
//calculate how big the comments are. (beyond the default height)
for i:=1 to specialstrings.count-1 do
inc(fHeight, fcanvas.textHeight(specialstrings[i]));
//calculae the custom headersize
for i:=0 to customheaderstrings.count-1 do
inc(fheight, fCanvas.TextHeight(customheaderstrings[i]));
inc(fHeight, spaceAboveLines+spaceBelowLines);
if ExtraLineRenderAbove<>nil then
begin
if AboveY=-1000 then //y doesn't care about center...
AboveY:=0;
if AboveX=-1000 then //center
AboveX:=(fHeaders.Items[fHeaders.Count-1].Width div 2) - (ExtraLineRenderAbove.Width div 2);
inc(fheight, AboveY);
inc(fHeight, ExtraLineRenderAbove.Height);
end;
if ExtraLineRenderBelow<>nil then
begin
if BelowY=-1000 then
BelowY:=0;
if BelowX=-1000 then //center
BelowX:=(fHeaders.Items[fHeaders.Count-1].Width div 2) - (ExtraLineRenderBelow.Width div 2);
inc(fheight, BelowY);
inc(fHeight, ExtraLineRenderAbove.Height);
end;
if (baseofsymbol>0) and (faddress=baseofsymbol) then
begin
parameters:='';
if textheight=-1 then
textheight:=fcanvas.TextHeight(symbolname);
fheight:=height+textheight+1+10;
if extrasymboldata<>nil then //more space needed for the local vars
fHeight:=fHeight+textheight*extrasymboldata.locals.count;
end;
refferencedbylinecount:=0;
if (dissectcode<>nil) and (dissectcode.done) then
begin
refferencedbystrings:=tstringlist.create;
buildReferencedByString(refferencedbystrings);
if refferencedbystrings.count>0 then
begin
fcanvas.Font.Style:=[fsBold];
if referencedbylineheight=-1 then
referencedbylineheight:=fcanvas.textheight('xxx');
refferencedbylinecount:=refferencedbystrings.count;
refferencedbyheight:=refferencedbylinecount*referencedbylineheight;
fheight:=height+refferencedbyheight;
fcanvas.Font.Style:=[];
end;
end;
fisJump:=visibleDisassembler.LastDisassembleData.isjump;
if fisJump then
begin
fisjump:=cefuncproc.isjumporcall(faddress, fJumpsTo);
if visibleDisassembler.LastDisassembleData.iscall then
fjumpcolor:= TDisassemblerview(owner).jlCallColor
else
begin
if visibleDisassembler.LastDisassembleData.isconditionaljump then
fjumpcolor:=TDisassemblerview(owner).jlConditionalJumpColor
else
fjumpcolor:=TDisassemblerview(owner).jlUnConditionalJumpColor ;
end;
end;
if debuggerthread<>nil then
bp:=debuggerthread.isBreakpoint(faddress,0,true)
else
bp:=nil;
isbp:=(bp<>nil) and (bp.breakpointTrigger=bptExecute) and (bp.active or (bp.breakpointMethod=bpmException) ) and (bp.markedfordeletion=false);
isultimap:=((frmUltimap2<>nil) and frmUltimap2.IsMatchingAddress(faddress)) or ((frmCodeFilter<>nil) and (frmCodeFilter.isBreakpoint(faddress,b) ));
isultimap:=isultimap or dbvm_isBreakpoint(faddress,PA,BO, b); //mark dbvm internal breakpoints with the same color as an ultimap bp
if selected then
begin
if not isbp then
begin
//default
if not focused then
begin
if isultimap then
begin
fcanvas.Brush.Color:=fcolors^[csSecondaryHighlightedUltimap].backgroundcolor;
fcanvas.Font.Color:=fcolors^[csSecondaryHighlightedUltimap].normalcolor;
end
else
begin
fcanvas.Brush.Color:=fcolors^[csSecondaryHighlighted].backgroundcolor;
fcanvas.Font.Color:=fcolors^[csSecondaryHighlighted].normalcolor;
end;
end
else
begin
if isultimap then
begin
fcanvas.Brush.Color:=fcolors^[csHighlightedUltimap].backgroundcolor;
fcanvas.Font.Color:=fcolors^[csHighlightedUltimap].normalcolor;
end
else
begin
fcanvas.Brush.Color:=fcolors^[csHighlighted].backgroundcolor;
fcanvas.Font.Color:=fcolors^[csHighlighted].normalcolor;
end;
end;
end
else
begin
//it's a breakpoint
fcanvas.Brush.Color:=fcolors^[csHighlightedbreakpoint].backgroundcolor;
fcanvas.Font.Color:=fcolors^[csHighlightedbreakpoint].normalcolor;
end;
fcanvas.Refresh;
end
else
begin
//not selected
if isbp then
begin
fCanvas.Brush.Color:=fcolors^[csbreakpoint].backgroundcolor;
fCanvas.font.Color:=fcolors^[csbreakpoint].normalcolor;
end else
begin
if isultimap then
begin
fCanvas.Brush.Color:=fcolors^[csUltimap].backgroundcolor;
fCanvas.font.Color:=fcolors^[csUltimap].normalcolor;
end
else
begin
fCanvas.Brush.Color:=fcolors^[csNormal].backgroundcolor;
fCanvas.font.Color:=fcolors^[csNormal].normalcolor;
end;
end;
fcanvas.Refresh
end;
//height may not change after this
fcanvas.FillRect(rect(0,top,fbitmap.width,top+height));
inc(linestart, spaceAboveLines);
if ExtraLineRenderAbove<>nil then
begin
//render the image above
linestart:=linestart+AboveY;
fcanvas.Draw(abovex, linestart, ExtraLineRenderAbove);
linestart:=linestart+ExtraLineRenderAbove.height;
end;
if (baseofsymbol>0) and (faddress=baseofsymbol) then
begin
fcanvas.Font.Style:=[fsbold];
parameters:='';
result:='';
if extrasymboldata<>nil then
begin
result:=extrasymboldata.return;
if result<>'' then
result:=result+' ';
locations:='';
parameters:='(';
if extrasymboldata.parameters.count>0 then
begin
for i:=0 to extrasymboldata.parameters.count-1 do
begin
if i=0 then
parameters:=parameters+extrasymboldata.parameters[i].vtype+' '+extrasymboldata.parameters[i].name
else
parameters:=parameters+', '+extrasymboldata.parameters[i].vtype+' '+extrasymboldata.parameters[i].name;
if i=0 then
locations:=' : '+extrasymboldata.parameters[i].name+'='+extrasymboldata.parameters[i].position
else
locations:=locations+' - '+extrasymboldata.parameters[i].name+'='+extrasymboldata.parameters[i].position;
end;
end
else
parameters:=parameters+extrasymboldata.simpleparameters;
parameters:=parameters+')'+locations;
end;
fcanvas.TextOut(fHeaders.Items[0].Left+5,linestart+5,AnsiToUtf8(result+symbolname+parameters));
linestart:=linestart+fcanvas.TextHeight(symbolname)+1+10;
fcanvas.Font.Style:=[];
//render the local vars
if extrasymboldata<>nil then
begin
linestart:=linestart-5; //go back a bit
for i:=0 to extrasymboldata.locals.count-1 do
begin
parameters:=extrasymboldata.locals[i].vtype+' '+extrasymboldata.locals[i].name;
if extrasymboldata.locals[i].position<>'' then
parameters:=parameters+'('+extrasymboldata.locals[i].position+')';
fcanvas.TextOut(fHeaders.Items[0].Left+5,linestart,AnsiToUtf8(parameters));
linestart:=linestart+textheight;
end;
linestart:=linestart+5;
end;
end;
if (refferencedbylinecount>0) then
begin
refferencedByStart:=linestart;
fcanvas.Font.Style:=[fsBold];
for i:=0 to refferencedbylinecount-1 do
begin
fcanvas.TextOut(fHeaders.Items[0].Left+5,linestart,AnsiToUtf8(refferencedbystrings[i]));
linestart:=linestart+fcanvas.TextHeight(refferencedbystrings[i]);
end;
fcanvas.Font.Style:=[];
end;
if customheaderstrings.count>0 then
begin
//render the custom header
for i:=0 to customheaderstrings.count-1 do
begin
fcanvas.TextOut(fHeaders.Items[0].Left,linestart,AnsiToUtf8(customheaderstrings[i]));
linestart:=linestart+fcanvas.TextHeight(customheaderstrings[i]);
end;
end;
if iscurrentinstruction then
addressString:='>>'+addressString;
//set pointers to strings
paddressstring:=nil;
pbytestring:=nil;
popcodestring:=nil;
pspecialstring:=nil;
if length(addressstring)>0 then
paddressstring:=@addressstring[1];
if length(bytestring)>0 then
pbytestring:=@bytestring[1];
if length(opcodestring)>0 then
popcodestring:=@opcodestring[1];
if length(specialstring)>0 then
pspecialstring:=@specialstring[1];
textcolor:=fcanvas.Font.Color;
handledisassemblerplugins(@paddressString, @pbytestring, @popcodestring, @pspecialstring, @textcolor);
fcanvas.font.color:=textcolor;
fcanvas.TextRect(rect(fHeaders.Items[0].Left, linestart, fHeaders.Items[0].Right, linestart+height), fHeaders.Items[0].Left+1,linestart, paddressString);
// fcanvas.TextRect(rect(fHeaders.Items[1].Left, linestart, fHeaders.Items[1].Right, linestart+height),fHeaders.Items[1].Left+1,linestart, pbytestring);
DrawTextRectWithColor(rect(fHeaders.Items[1].Left, linestart, fHeaders.Items[1].Right, linestart+height),fHeaders.Items[1].Left+1,linestart, pbytestring);
fcanvas.font.Style:=fcanvas.font.Style+[fsBold];
i:=DrawTextRectWithColor(rect(fHeaders.Items[2].Left, linestart, fHeaders.Items[2].Right, linestart+height),fHeaders.Items[2].Left+1,linestart, popcodestring);
fcanvas.font.Style:=fcanvas.font.Style-[fsBold];
inc(i, fcanvas.TextWidth(' '));
j:=fcanvas.textwidth('XXXXXXX');
if i>j then
i:=fHeaders.Items[2].Left+1+i+fcanvas.textwidth(' ')
else
i:=fHeaders.Items[2].Left+1+j;
DrawTextRectWithColor(rect(fHeaders.Items[2].Left, linestart, fHeaders.Items[2].Right, linestart+height),i,linestart, parameterstring);
fInstructionCenter:=linestart+(fcanvas.TextHeight(opcodestring) div 2);
if specialstrings.Count>0 then
begin
for i:=0 to specialstrings.Count-1 do
begin
fcanvas.TextRect(rect(fHeaders.Items[3].Left, linestart, fHeaders.Items[3].Right, linestart+height),fHeaders.Items[3].Left+1,linestart, specialstrings[i]);
inc(linestart, fcanvas.GetTextHeight(specialstrings[i]));
end;
end
else
inc(linestart, fcanvas.GetTextHeight(parameterstring));
if ExtraLineRenderBelow<>nil then
begin
//render the image below
linestart:=linestart+BelowY;
fcanvas.Draw(belowx, linestart, ExtraLineRenderBelow);
linestart:=linestart+ExtraLineRenderBelow.height; //not really needed as it's the last one
end;
if focused and (tdisassemblerview(fowner).hidefocusrect=false) then
fcanvas.DrawFocusRect(rect(0,top,fbitmap.width,top+height));
if selected then //restore
begin
fCanvas.Brush.Color:=fcolors^[csNormal].backgroundcolor;
fCanvas.font.Color:=fcolors^[csNormal].normalcolor;
fcanvas.Refresh;
end;
if refferencedbystrings<>nil then
freeandnil(refferencedbystrings);
end;
function TDisassemblerLine.DrawTextRectWithColor(const ARect: TRect; X, Y: integer; const Text: string): integer;
var defaultfontcolor, defaultbrushcolor: TColor;
i: integer;
start,startx: integer;
s,s2: string;
colorcode: integer; //0=normal, 1=hex, 2=reg, 3=symbol 4=rgb
bcolorcode: integer; //0=normal, 1=rgb
rgbcolor: integer;
brgbcolor: integer;
colorstate: TDisassemblerViewColorsState;
ts: TTextStyle;
procedure setcolor;
begin
if isselected then
begin
if isbp then
colorstate:=csSecondaryHighlightedbreakpoint
else
if isultimap then
colorstate:=csSecondaryHighlightedUltimap
else
colorstate:=csSecondaryHighlighted;
if focused then
begin
if isbp then
colorstate:=csHighlightedbreakpoint
else
if isultimap then
colorstate:=csHighlightedUltimap
else
colorstate:=csHighlighted;
end;
end
else
begin
if isbp then
colorstate:=csBreakpoint
else
if isultimap then
colorstate:=csUltimap
else
colorstate:=csNormal;
end;
case colorcode of
0: fcanvas.font.color:=fcolors^[colorstate].normalcolor;
1: fcanvas.font.color:=fcolors^[colorstate].hexcolor;
2: fcanvas.font.color:=fcolors^[colorstate].registercolor;
3: fcanvas.font.color:=fcolors^[colorstate].symbolcolor;
4: fcanvas.font.color:=rgbcolor;
end;
case bcolorcode of
0:
begin
ts:=fcanvas.TextStyle;
ts.Opaque:=true;
fcanvas.TextStyle:=ts;
fcanvas.Brush.color:=defaultbrushcolor;
end;
1:
begin
ts:=fcanvas.TextStyle;
ts.Opaque:=true;
fcanvas.TextStyle:=ts;
fcanvas.Brush.color:=brgbcolor;
end;
end;
end;
begin
defaultbrushcolor:=fcanvas.Brush.color;
defaultfontcolor:=fcanvas.Font.color;
start:=1;
startx:=x;
s:='';
i:=1;
colorcode:=0;
bcolorcode:=0;
if processhandler.SystemArchitecture=archx86 then
begin
while i<=length(text) do
begin
case text[i] of
'{':
begin
setcolor;
s:=copy(text, start,i-start);
fcanvas.TextRect(ARect,x,y,AnsiToUtf8(s));
x:=x+fcanvas.TextWidth(s)+1;
inc(i);
while i<=length(text) do
begin
case text[i] of
'N':
begin
colorcode:=0;
bcolorcode:=0;
end;
'H': colorcode:=1;
'R': colorcode:=2;
'S': colorcode:=3;
'B': //followed by RRGGBB colorcode
begin
s2:=copy(text, i+1,6);
if trystrtoint('$'+s2, brgbcolor) then bcolorcode:=1;
inc(i,6);
end;
'C': //followed by RRGGBB colorcode
begin
s2:=copy(text, i+1,6);
if trystrtoint('$'+s2, rgbcolor) then colorcode:=4;
inc(i,6);
end;
'}':
begin
inc(i);
break;
end;
//else raise exception.create(rsInvalidDisassembly);
end;
inc(i);
end;
start:=i;
end;
else inc(i);
end;
end;
end
else
i:=length(text);
setcolor;
s:=copy(text, start,i-start);
fcanvas.TextRect(ARect,x,y,AnsiToUtf8(s));
fcanvas.Font.color:=defaultfontcolor;
fcanvas.brush.color:=defaultbrushcolor;
x:=x+fcanvas.TextWidth(s);
result:=x-startx;
end;
procedure TDisassemblerLine.handledisassemblerplugins(addressStringPointer: pointer; bytestringpointer: pointer; opcodestringpointer: pointer; specialstringpointer: pointer; textcolor: PColor);
begin
//obsolete
if pluginhandler<>nil then
pluginhandler.handledisassemblerplugins(faddress, addressStringPointer, bytestringpointer, opcodestringpointer, specialstringpointer, textcolor);
end;
function TDisassemblerLine.getHeight: integer;
begin
result:=height;
end;
function TDisassemblerLine.getTop: integer;
begin
result:=ftop;
end;
destructor TDisassemblerLine.destroy;
begin
freeandnil(specialstrings);
inherited destroy;
end;
constructor TDisassemblerLine.create(owner: TObject; bitmap: TBitmap; headersections: THeaderSections; colors: PDisassemblerViewColors);
begin
fowner:=owner;
fCanvas:=bitmap.canvas;
fBitmap:=bitmap;
fheaders:=headersections;
boldheight:=-1; //bypass for memory leak
textheight:=-1;
referencedbylineheight:=-1;
fcolors:=colors;
fheight:=fCanvas.TextHeight('X');
fDefaultHeight:=-1;
specialstrings:=tstringlist.create;
customheaderstrings:=tstringlist.create;
end;
end.