📄 observerdisassembler.pas
字号:
//////////////////////////////////////////////////////////////////////
// //
// observerDisassembler.pas: Interactive disassembler //
// //
// The contents of this file are subject to the Bottled Light //
// Public License Version 1.0 (the "License"); you may not use this //
// file except in compliance with the License. You may obtain a //
// copy of the License at http://www.bottledlight.com/BLPL/ //
// //
// Software distributed under the License is distributed on an //
// "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or //
// implied. See the License for the specific language governing //
// rights and limitations under the License. //
// //
// The Original Code is the Mappy VM User Interface, released //
// April 1st, 2003. The Initial Developer of the Original Code is //
// Bottled Light, Inc. Portions created by Bottled Light, Inc. are //
// Copyright (C) 2001-2003 Bottled Light, Inc. All Rights Reserved. //
// //
// Author(s): //
// Michael Noland (joat), michael@bottledlight.com //
// //
// Changelog: //
// 1.0: First public release (April 1st, 2003) //
// //
// Notes: //
// None at present. //
// //
//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
unit observerDisassembler; ///////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
interface ////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms,
Dialogs, Menus, StdCtrls, SynEdit, SynMemo, IniFiles, ImgList,
Math, CheckLst, ExtCtrls, ToolWin, ComCtrls, arm_disass,
cpuObservers, jdevDisassemblyDialog, dwarfUtils,
observerCSource, console, clipbrd, nexus, AddressSpace,
dbgBreakpoints;
//////////////////////////////////////////////////////////////////////
type
TDebuggerLineInfo = (dlCurrentLine, dlBreakpointLine, dlExecutableLine);
TDebuggerLineInfos = set of TDebuggerLineInfo;
TjdevDisassembler = class(TCpuObserver)
listingMenu: TPopupMenu;
mBrowseTo: TMenuItem;
scrollbar: TScrollBar;
imglGutterGlyphs: TImageList;
splitter: TSplitter;
registersPanel: TPanel;
imglActions: TImageList;
mReturntoPC: TMenuItem;
regDisplay: TListBox;
regEditor: TEdit;
Splitter1: TSplitter;
flagsDisplay: TCheckListBox;
conditionDisplay: TCheckListBox;
registersMenu: TPopupMenu;
mIncrementRegister: TMenuItem;
mDecrementRegister: TMenuItem;
mZeroRegister: TMenuItem;
mChangeRegister: TMenuItem;
N2: TMenuItem;
mMarkRegisters: TMenuItem;
listbox: TListBox;
gutter: TPaintBox;
N4: TMenuItem;
mDisasmInARM: TMenuItem;
mDisasmInThumb: TMenuItem;
mDisasmFollowsCPU: TMenuItem;
mShowExactOpcodes: TMenuItem;
N1: TMenuItem;
mChangeFont: TMenuItem;
fontDialog: TFontDialog;
N3: TMenuItem;
mChangeFont2: TMenuItem;
bTools: TButton;
bHelp: TButton;
Addlabel1: TMenuItem;
RemoveLabel1: TMenuItem;
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure scrollbarChange(Sender: TObject);
procedure BrowseToAddress(Sender: TObject);
procedure listingDblClick(Sender: TObject);
procedure DisassembleInARM(Sender: TObject);
procedure DisassembleInThumb(Sender: TObject);
procedure DisassemblyFollowsCPU(Sender: TObject);
procedure FormMouseWheelDown(Sender: TObject; Shift: TShiftState; MousePos: TPoint; var Handled: Boolean);
procedure FormMouseWheelUp(Sender: TObject; Shift: TShiftState; MousePos: TPoint; var Handled: Boolean);
procedure FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
procedure FormResize(Sender: TObject);
procedure listingMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
procedure ReturnToCurrentPC(Sender: TObject);
procedure IncrementRegister(Sender: TObject);
procedure DecrementRegister(Sender: TObject);
procedure ZeroRegister(Sender: TObject);
procedure ChangeRegister(Sender: TObject);
procedure MarkRegisters(Sender: TObject);
procedure regDisplayClick(Sender: TObject);
procedure regEditorKeyPress(Sender: TObject; var Key: Char);
procedure conditionDisplayClickCheck(Sender: TObject);
procedure flagsDisplayClickCheck(Sender: TObject);
procedure regDisplayDblClick(Sender: TObject);
procedure listboxMeasureItem(Control: TWinControl; Index: Integer; var Height: Integer);
procedure listboxDrawItem(Control: TWinControl; Index: Integer; aRect: TRect; State: TOwnerDrawState);
procedure ToggleShowExactOpcodes(Sender: TObject);
procedure regDisplayDrawItem(Control: TWinControl; Index: Integer; Rect: TRect; State: TOwnerDrawState);
procedure FormMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
procedure AddLabel(Sender: TObject);
procedure RemoveLabel(Sender: TObject);
procedure ChangeFont(Sender: TObject);
procedure FormShow(Sender: TObject);
procedure ShowMenu(Sender: TObject);
procedure ShowHelp(Sender: TObject);
private
delta: integer;
amUpdating, following: boolean;
regEditing: integer;
lastList: TStringList;
marked: TvmRegisterFile;
lastRegs: TvmRegisterFile;
amMarked: boolean;
lastY, lastI: integer;
fontString: string;
showExactOpcodes: boolean;
procedure MarkTheRegisters;
procedure UpdateListing;
function linesInDisasm: integer;
procedure CalculateDelta;
public
procedure UpdateObserver; override;
class function OCaption: string; override;
procedure LoadSettings(ini: TIniFile); override;
procedure SaveSettings(ini: TIniFile); override;
end;
//////////////////////////////////////////////////////////////////////
var
jdevDisassembler: TjdevDisassembler;
//////////////////////////////////////////////////////////////////////
implementation ///////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
{$R *.DFM}
//////////////////////////////////////////////////////////////////////
procedure TjdevDisassembler.FormCreate(Sender: TObject);
begin
lastY := 0;
lastI := 0;
// Pick an initial position to show
amMarked := false;
amUpdating := true;
ReturnToCurrentPC(Sender);
amUpdating := false;
vmGetRegisters(lastRegs);
// Move the register editor out of the way
regEditor.Top := -regEditor.height;
regEditing := -1;
lastList := TStringList.Create;
scrollBar.SmallChange := 4;
scrollBar.LargeChange := 32;
listbox.DoubleBuffered := true;
regDisplay.DoubleBuffered := true;
conditionDisplay.DoubleBuffered := true;
flagsDisplay.DoubleBuffered := true;
HelpContext := LinkHelp('disassembler.html');
end;
//////////////////////////////////////////////////////////////////////
procedure TjdevDisassembler.FormDestroy(Sender: TObject);
begin
// Kill the disassember
jdevDisasmDialog.Close;
lastList.Free;
end;
//////////////////////////////////////////////////////////////////////
class function TjdevDisassembler.OCaption: string;
begin
Result := 'Disassembler';
end;
//////////////////////////////////////////////////////////////////////
procedure TjdevDisassembler.UpdateObserver;
begin
// Update the disassembler
following := true;
UpdateListing;
// Grab the state off the cpu
// if amMarked then markTheRegisters;
vmGetRegisters(lastRegs);
// Update the register display
regDisplay.Items.BeginUpdate;
regDisplay.Items.Clear;
regDisplay.Items.Add(Format('R0 %.8x', [lastRegs.regs[0]]));
regDisplay.Items.Add(Format('R1 %.8x', [lastRegs.regs[1]]));
regDisplay.Items.Add(Format('R2 %.8x', [lastRegs.regs[2]]));
regDisplay.Items.Add(Format('R3 %.8x', [lastRegs.regs[3]]));
regDisplay.Items.Add(Format('R4 %.8x', [lastRegs.regs[4]]));
regDisplay.Items.Add(Format('R5 %.8x', [lastRegs.regs[5]]));
regDisplay.Items.Add(Format('R6 %.8x', [lastRegs.regs[6]]));
regDisplay.Items.Add(Format('R7 %.8x', [lastRegs.regs[7]]));
regDisplay.Items.Add(Format('R8 %.8x', [lastRegs.regs[8]]));
regDisplay.Items.Add(Format('R9 %.8x', [lastRegs.regs[9]]));
regDisplay.Items.Add(Format('R10 %.8x', [lastRegs.regs[10]]));
regDisplay.Items.Add(Format('R11 %.8x', [lastRegs.regs[11]]));
regDisplay.Items.Add(Format('R12 %.8x', [lastRegs.regs[12]]));
regDisplay.Items.Add(Format('R13 %.8x', [lastRegs.regs[13]]));
regDisplay.Items.Add(Format('LR %.8x', [lastRegs.regs[14]]));
regDisplay.Items.Add(Format('PC %.8x', [lastRegs.regs[15]]));
regDisplay.Items.Add(Format('CPSR %.8x', [lastRegs.regs[16]]));
regDisplay.Items.EndUpdate;
// Update the CPSR flag display
conditionDisplay.Checked[0] := lastRegs.regs[16] and SR_N <> 0;
conditionDisplay.Checked[1] := lastRegs.regs[16] and SR_Z <> 0;
conditionDisplay.Checked[2] := lastRegs.regs[16] and SR_C <> 0;
conditionDisplay.Checked[3] := lastRegs.regs[16] and SR_V <> 0;
flagsDisplay.Checked[0] := lastRegs.regs[16] and SR_I <> 0;
flagsDisplay.Checked[1] := lastRegs.regs[16] and SR_F <> 0;
flagsDisplay.Checked[2] := lastRegs.regs[16] and SR_T <> 0;
end;
//////////////////////////////////////////////////////////////////////
procedure TjdevDisassembler.UpdateListing;
var
i, y: integer;
begin
if not Assigned(lastList) then Exit;
if amUpdating then Exit;
if linesInDisasm < 1 then Exit;
try
amUpdating := true;
disassembler.UseExactOpcodes := ShowExactOpcodes;
// Set the scrollbar change rates
CalculateDelta;
scrollBar.LargeChange := (linesInDisasm-1)*delta;
scrollBar.SmallChange := delta;
// Actually disassemble the program
lastList.Clear;
disassembler.Emulate(scrollbar.Position, linesInDisasm+1, lastList);
// listbox.items.BeginUpdate;
listbox.Items.Clear;
i := 0; lastY := 0;
y := 0; lastI := 0;
while (i < lastList.Count) and (y < listbox.height) do begin
lastY := y;
lastI := i;
y := y + listbox.ItemHeight;
if bpmSoft in vmIsBreakpoint(uint32(lastList.objects[i])) then y := y + listbox.ItemHeight;
if y < listbox.height then listBox.Items.AddObject(lastList.strings[i], lastList.objects[i]);
Inc(i);
end;
gutter.Canvas.Brush.Color := listbox.Brush.color;
gutter.Canvas.FillRect(Rect(0, 0, gutter.Width, gutter.Height));
// listbox.items.EndUpdate;
// listing.Lines.AddStrings(lastList);
except
on e: Exception do e.Free;
end;
amUpdating := false;
end;
//////////////////////////////////////////////////////////////////////
procedure TjdevDisassembler.scrollbarChange(Sender: TObject);
begin
following := false;
UpdateListing;
end;
//////////////////////////////////////////////////////////////////////
procedure TjdevDisassembler.BrowseToAddress(Sender: TObject);
var
st: string;
begin
try
st := Trim(InputBox('Mappy VM', 'Enter the address (in hex) to display', Format('$%8.8x', [vmCurrentPC])));
if Length(st) > 0 then begin
if st[1] <> '$' then st := '$' + st;
scrollBar.Position := StrToIntDef(st, vmCurrentPC);
end;
except
on e: EConvertError do e.Free;
end;
end;
//////////////////////////////////////////////////////////////////////
procedure TjdevDisassembler.listingDblClick(Sender: TObject);
{var
x, x1, y: integer;
l: string;
begin
// Find the cursor position
x := listing.caretX;
y := listing.caretY;
// Try to isolate a number at the cursor position
if (y > 0) and (y <= listing.Lines.Count) then begin
l := listing.Lines[y-1];
if x > 18 then begin
x1 := x;
while (x > 0) and (l[x] <> ' ') do Dec(x);
while (x1 <= Length(l)) and (l[x1] <> ' ') do Inc(x1);
Inc(x);
l := Trim(Copy(l, x, x1-x+1));
while (Length(l) > 0) and (l[1] in ['#', '=', ',']) do Delete(l, 1, 1);
if (Length(l) > 0) and (l[1] <> '$') then l := '$' + l;
// Branch to the new location
scrollbar.Position := StrToIntDef(l, scrollbar.Position);
end;
end;}
begin
//
end;
//////////////////////////////////////////////////////////////////////
procedure TjdevDisassembler.DisassembleInARM(Sender: TObject);
begin
mDisasmInARM.Checked := true;
UpdateObserver;
end;
//////////////////////////////////////////////////////////////////////
procedure TjdevDisassembler.DisassembleInThumb(Sender: TObject);
begin
mDisasmInThumb.Checked := true;
UpdateObserver;
end;
//////////////////////////////////////////////////////////////////////
procedure TjdevDisassembler.DisassemblyFollowsCPU(Sender: TObject);
begin
mDisasmFollowsCPU.Checked := true;
UpdateObserver;
end;
//////////////////////////////////////////////////////////////////////
procedure TjdevDisassembler.FormMouseWheelDown(Sender: TObject; Shift: TShiftState; MousePos: TPoint; var Handled: Boolean);
begin
scrollbar.Position := Min(scrollbar.Position + delta, scrollbar.Max);
end;
//////////////////////////////////////////////////////////////////////
procedure TjdevDisassembler.FormMouseWheelUp(Sender: TObject; Shift: TShiftState; MousePos: TPoint; var Handled: Boolean);
begin
scrollbar.Position := Max(scrollbar.Position - delta, scrollbar.Min);
end;
//////////////////////////////////////////////////////////////////////
procedure TjdevDisassembler.FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
var
i: integer;
st: string;
begin
case Key of
VK_PRIOR: scrollbar.Position := Max(scrollbar.Position - scrollbar.LargeChange, scrollbar.Min);
VK_NEXT: scrollbar.Position := Min(scrollbar.Position + scrollbar.LargeChange, scrollbar.Max);
Ord('C'), Ord('c'): if ssCtrl in Shift then
if listbox.SelCount > 0 then begin
st := '';
for i := 0 to listbox.Items.Count - 1 do
if listbox.Selected[i] then st := st + listbox.Items.Strings[i] + #13#10;
Clipboard.SetTextBuf(PChar(st));
end;
end;
end;
//////////////////////////////////////////////////////////////////////
procedure TjdevDisassembler.FormResize(Sender: TObject);
begin
following := false;
if Height <> 0 then
UpdateListing;
end;
//////////////////////////////////////////////////////////////////////
procedure TjdevDisassembler.listingMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
{var
x1: integer;
l: string;
pt: TPoint;}
begin
{ // Convert the mouse position to a text position
pt.x := x;
pt.y := y;
pt := listing.PixelsToRowColumn(pt);
x := pt.x;
y := pt.y;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -