⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 observerdisassembler.pas

📁 一个不出名的GBA模拟器
💻 PAS
📖 第 1 页 / 共 2 页
字号:
//////////////////////////////////////////////////////////////////////
//                                                                  //
// 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 + -