////////////////////////////////////////////////////////////////////// // // // jdevDisassemblyDialog.pas: Scripted disassembly dialog // // This provides an interface for the user to save a disasm of // // multiple sections of memory in different modes. // // // // 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: // // Needs rewriting to make the output directly recompile in GAS. // // // ////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////// unit jdevDisassemblyDialog; ////////////////////////////////////////// ////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////// interface //////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////// uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, ComCtrls, StdCtrls, console, Menus, arm_disass, nexus, AddressSpace; ////////////////////////////////////////////////////////////////////// type TOnDDialogClose = procedure (executed: boolean) of object; TjdevDisasmDialog = class(TForm) eDestFile: TEdit; browseButton: TButton; lDestination: TLabel; saveDialog: TSaveDialog; tasks: TListView; lCommands: TLabel; okButton: TButton; cancelButton: TButton; rTargetARM: TRadioButton; rTargetGAS: TRadioButton; lTargetASM: TLabel; addButton: TButton; removeButton: TButton; eLabel: TEdit; eMode: TComboBox; eSize: TEdit; eAddress: TEdit; mainMenu: TMainMenu; mFile: TMenuItem; mLoadScript: TMenuItem; mSaveScript: TMenuItem; openDialog: TOpenDialog; procedure addButtonClick(Sender: TObject); procedure removeButtonClick(Sender: TObject); procedure browseButtonClick(Sender: TObject); procedure okButtonClick(Sender: TObject); procedure cancelButtonClick(Sender: TObject); procedure tasksCompare(Sender: TObject; Item1, Item2: TListItem; Data: Integer; var Compare: Integer); procedure FormCreate(Sender: TObject); procedure LoadScript(Sender: TObject); procedure SaveScript(Sender: TObject); private { Private declarations } public { Public declarations } procedure AddEntry(title, address, size, mode: string); end; ////////////////////////////////////////////////////////////////////// var jdevDisasmDialog: TjdevDisasmDialog; ////////////////////////////////////////////////////////////////////// implementation /////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////// {$R *.DFM} ////////////////////////////////////////////////////////////////////// procedure TjdevDisasmDialog.AddEntry(title, address, size, mode: string); var item: TListItem; st: string; base, count: uint32; begin // Get the address st := Trim(address); if Length(st) < 1 then begin Beep; Exit; end; if st[1] <> '$' then st := '$' + st; base := StrToInt(st); // Get the size st := Trim(size); if Length(st) < 1 then begin Beep; Exit; end; count := StrToInt(st); // Add the item item := tasks.Items.Add; item.Caption := title; item.SubItems.Add('$'+IntToHex(base and not 1, 8)); item.SubItems.Add(IntToStr(count)); // Get the mode if Uppercase(mode) = 'ARM' then item.SubItems.Add('ARM') else if Uppercase(mode) = 'THUMB' then item.SubItems.Add('Thumb') else item.SubItems.Add('Data'); // Sort the list tasks.CustomSort(nil, 0); end; ////////////////////////////////////////////////////////////////////// procedure TjdevDisasmDialog.addButtonClick(Sender: TObject); begin AddEntry(eLabel.Text, eAddress.Text, eSize.Text, eMode.Text) end; ////////////////////////////////////////////////////////////////////// procedure TjdevDisasmDialog.removeButtonClick(Sender: TObject); begin if Assigned(tasks.Selected) then tasks.Selected.Delete; end; ////////////////////////////////////////////////////////////////////// procedure TjdevDisasmDialog.browseButtonClick(Sender: TObject); begin saveDialog.DefaultExt := 'asm'; saveDialog.Filter := 'Assembler File|*.asm;*.s|All Files|*.*'; if saveDialog.Execute then eDestFile.Text := saveDialog.FileName; end; ////////////////////////////////////////////////////////////////////// procedure TjdevDisasmDialog.okButtonClick(Sender: TObject); var item: TListItem; i, k: uint32; text: TStringList; count, base: uint32; st: string; begin if eDestFile.Text = '' then begin Beep; Exit; end; disassembler.showJunk := false; disassembler.useTabs := true; // Create the disasm file and write a prologue text := TStringList.Create; text.Add('Disassembly produced by Mappy VM'); text.Add('Created on ' + DateTimeToStr(Now)); // Add the labels to the disassembler first for i := 0 to tasks.Items.Count - 1 do begin item := tasks.Items.Item[i]; base := StrToIntDef(item.SubItems.Strings[0], 0); disassembler.AddMapping(base, item.Caption); end; // Disassemble all the tasks in the list for i := 0 to tasks.Items.Count - 1 do begin // Get a new task item := tasks.Items.Item[i]; // Parse the label, base address, length, and CPU mode of the entry base := StrToIntDef(item.SubItems.Strings[0], 0); count := StrToIntDef(item.SubItems.Strings[1], 0); disassembler.thumbMode := Uppercase(item.SubItems.Strings[2]) = 'THUMB'; // Disassemble this task if count > 0 then begin text.Add(''); if Uppercase(item.SubItems.Strings[2]) = 'DATA' then begin k := 0; st := item.Caption + ' '; while k < count do begin if k and 7 = 0 then begin Delete(st, Length(st)-1, 2); text.Add(st); st := IntToHex(base, 8) + #9'DCD'#9; end; st := st + '$' + IntToHex(vmReadWord(base), 8) + ', '; Inc(base, 4); Inc(k); end; if count and 7 <> 0 then begin Delete(st, Length(st)-1, 2); text.Add(st); end; end else begin // text.Add(item.Caption + #9); disassembler.Emulate(base, count, text); end; end; end; // Save the disassembly to a file text.SaveToFile(eDestFile.Text); text.Free; // Clear the task list // tasks.Items.Clear; disassembler.showJunk := true; disassembler.useTabs := false; end; ////////////////////////////////////////////////////////////////////// procedure TjdevDisasmDialog.cancelButtonClick(Sender: TObject); begin Close; end; ////////////////////////////////////////////////////////////////////// procedure TjdevDisasmDialog.tasksCompare(Sender: TObject; Item1, Item2: TListItem; Data: Integer; var Compare: Integer); begin if (Item2.SubItems.Count > 0) and (Item2.SubItems.Count > 0) then begin Compare := StrComp(PChar(Item1.SubItems.Strings[0]), PChar(Item2.SubItems.Strings[0])); if Compare = 0 then Compare := StrComp(PChar(Item1.Caption), PChar(Item2.Caption)); end else Compare := 0; end; ////////////////////////////////////////////////////////////////////// procedure TjdevDisasmDialog.FormCreate(Sender: TObject); begin HelpContext := LinkHelp('disassembler_script.html'); eDestFile.Text := ''; eMode.ItemIndex := 0; end; ////////////////////////////////////////////////////////////////////// procedure TjdevDisasmDialog.LoadScript(Sender: TObject); function HaxorLeft(var st: string): string; var i: integer; begin i := Pos(#9, st); if i = 0 then i := Length(st)+1; Result := Copy(st, 1, i-1); Delete(st, 1, i); end; var index: integer; items: TStringList; line, a, b, c, d: string; begin openDialog.DefaultExt := 'asr'; openDialog.Filter := 'Assembly Script Resource|*.asr;*.s|All Files|*.*'; if openDialog.Execute then begin // Load the file items := TStringList.Create; items.LoadFromFile(openDialog.FileName); // A touch of da crude error checking if (items.Count = 0) or (Copy(Uppercase(items.Strings[0]), 1, 4) <> 'ASR1') then begin Beep; Exit; end; // Add the entries to the task list index := 1; tasks.Items.Clear; while index < items.Count do begin line := items.Strings[index]; a := HaxorLeft(line); b := HaxorLeft(line); c := HaxorLeft(line); d := HaxorLeft(line); AddEntry(a, b, c, d); Inc(index); end; // Close the file items.Free; end; end; ////////////////////////////////////////////////////////////////////// procedure TjdevDisasmDialog.SaveScript(Sender: TObject); var index: integer; items: TStringList; item: TListItem; begin saveDialog.DefaultExt := 'asr'; saveDialog.Filter := 'Assembly Script Resource|*.asr;*.s|All Files|*.*'; if saveDialog.Execute then begin // Create a string file items := TStringList.Create; items.Add('ASR1 - Generated by Mappy VM'); // Copy the task list to the file for index := 0 to tasks.Items.Count-1 do begin item := tasks.Items.Item[index]; items.Add(Format('%s'#9'%s'#9'%s'#9'%s', [item.Caption, item.SubItems.Strings[0], item.SubItems.Strings[1], item.SubItems.Strings[2]])); end; // Save and close it items.SaveToFile(saveDialog.FileName); items.Free; end; end; ////////////////////////////////////////////////////////////////////// end. //////////////////////////////////////////////////////////////////////